За последние 24 часа нас посетили 16827 программистов и 1641 робот. Сейчас ищут 906 программистов ...

Update таблицы через Active record. Нипанятна

Тема в разделе "Прочие вопросы по PHP", создана пользователем lexa, 12 апр 2009.

  1. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Есть Active record. Есть класс Post. Хочу знать, как его правильно апгрейдить.

    PHP:
    1. <?php
    2. $post = new Post(22); // 22 это id
    3. $post->field = 'Hello';
    4. $post->save();
    Фактически, запрос вида:
    [sql]update post set `field` = 'Hello' where id = 22[/sql]

    Но, а если я хочу PHP задействовать:
    PHP:
    1. <?php
    2. $post = new Post(22); // 22 это id
    3. $post->field .= 'Hello';
    4. $post->save();
    Я не понимаю принцип.

    В PHP же нет магических методов на всякие пуки, как в питоне. Как же узнать, что переменной делается append строки? Никак. Но тогда надо предварительно делать select. Но как, блин, его делать, если до метода save() ещё не определены изменяемые поля? То есть нельзя сделать select только того, что необходимо.

    Делать селект всего из таблицы post тоже тупо, ведь может быть тонна полей и часть из них немалого размера (text, blob).

    А если делать update одновременно и many-to-many связям:
    PHP:
    1. <?php
    2. $post = new Post(22); // 22 это id
    3. $post->field .= 'Hello';
    4. $post->categories = array(8, 12, 44)
    5. $post->save();
    То надо делать select и таблицам со связями?

    Это везде так тупо работает или только мне в голову лезет сплошная пое**нь?

    upd по поводу $post->field .= 'Hello' не совсем прав. Когда закончил плакать и биться головой об стену, то попробовал сделать и PHP прежде пропускает свойство через __get().

    Но всё равно не понятно с выборкой.
     
  2. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    Вообще не понял проблемы
    это типа ORM что-то?
     
  3. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    blob и text поля можно пометить как lazy
     
  4. topas

    topas Активный пользователь

    С нами с:
    16 авг 2006
    Сообщения:
    2.258
    Симпатии:
    36
    PHP:
    1. <?php
    2. $post = new Post(22); // SELECT id, title, user.name FROM ... WHERE ...
    3.  
    4. $post->field .= 'Hello'; // Равнозначно следующему:
    5. $post->__set('field', $post->__get('field') . 'Hello'); // SELECT field FROM ... WHERE post_id = 22
    6.  
    7. $post->categories = array(8, 12, 44);
    8. $post->__set('categories', array(8, 12, 44));
    9.  
    10. $post->save(); // UPDATE ... SET field1 = 'value1', field2 = 'value2' WHERE post_id = 22; DELETE ...; INSERT ...
    11.  
    Что конкретно непонятно?
     
  5. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Типа того. Между ними разницу особую не вижу, но она есть. :)

    Чтобы пометить их как lazy нужно в модели описать все поля. Это не айс получится.

    За код спасибо. Я так позже и понял.

    1. С выборкой всего. Делать select и insert кажется несколько глупым. Вместо одного запроса два. К тому же select делается всему.

    2. С выборкой связей. Поля не известны. Значит либо делать сразу огромный запрос с учётом всех связей, либо на каждое связующее свойство делать отдельный доп. запрос.

    3. Если выкинуть из селекта text и blob поля не явно (в селект вписать не text и не blob поля из show fields), то вообще три запроса вместо одного.

    PHP:
    1. <?php
    2. $post = new Post(4);
    3. $post->someBlob .= ' append'; // отсюда поехал select * from post. Или show fields из post и вставление полей в select. кроме тех, что с типом text или blob
    4. $post->someInt += 44;
    5.  
    6. $post->save(); // set `someBlob` = 'старый текст append', `someInt` = (`someInt` + 44)
    Сейчас у мну выбирается всё при встречи первого свойства. Свойству с именем как у связи много-ко-много делается +1 запрос и присваивается массив id`шек из таблице связей. Но это как-то не жвачно и не парнокопытно - не кошерно. :)
     
  6. topas

    topas Активный пользователь

    С нами с:
    16 авг 2006
    Сообщения:
    2.258
    Симпатии:
    36
    GROUP_CONCAT?
     
  7. kostyl

    kostyl Guest

    Может не в тему, а то я не сильно въезжаю но все же:
    PHP:
    1.  
    2. <?php
    3. $post = new Post(4);
    4. if (needJoin) {
    5.  $post->joinUser();
    6. }
    7. //а там чтото типа
    8. class Post {
    9.   public function __construct()
    10.   {
    11.     parent::AddProperty('property1', 'field1', array('type'=>'main'));
    12.     parent::AddProperty('property2', 'field2', array('type'=>'lazy'));
    13.   }
    14.    
    15.   public function joinUser()
    16.   {
    17.     parent::AddProperty('property3', 'field1', array('type'=>'left join', '......'))
    18.   }
    19.  
    20. }
    21.  
    Или это не то и вообще вигня?
     
  8. kostyl

    kostyl Guest

    не, все нормально....
    только забыл родителя дописать, а вообще тоже неплохо, только надо все методы типа join* объявлять до конкретного доступа... тогда один запрос будет всего лишь, а не куча ненужных докачек...
     
  9. kostyl

    kostyl Guest

    что никто не покритикует мой пример?
     
  10. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    kostyl, я не стал отписываться потому что думал ты пропустил мой пост, а потом увидел и прочёл:
    То есть чтобы поля пометить как lazy они должны быть известны (в твоём примере все остальные поля это main, как я понял). У мну скрипт про поля ничего не знает до тех пор пока не начинает их выбирать (по команде table.* в методе select()) или при манипуляциях с таблицой:
    PHP:
    1. <?
    2. $user = new User;
    3. $user['new_field'] = array('type' => 'varchar(255)'); // через массив
    4. $user->new_int = array('type' => 'int'); // через обьект
    5. $user->alter(); // тут идёт запрос show fields и сравниваеются поля: если есть изменение или поле новое, то делается alter
    С select:
    PHP:
    1. <?
    2. $user = new User;
    3. $user->select('*', 'group.*'); // * - синоним user.*. Тут поля не нужно выбирать. А вот команда group.* создаст left join user плюс сделает запос show fields
    4. $user->getArray(); // строим многомерный массив исходя из связей
    Так же решил сделать show fields при апдейте таблице и выбирать все поля, кроме text и blob.

    Единственный недостаток подхода - лишний запрос. Но он делается не часто - апдейт ведь не самая частая операция. А в случае с select лишнего запроса можно избежать перечисляя необходимые при выборе поля:
    PHP:
    1. <?
    2. $user->select('*', 'group.id', 'group.name');
     
  11. kostyl

    kostyl Guest

    ну я тоже перечисляю, только я все спрятал. А в моем примере joinUser() можно в __get засунуть, тогда по первому доступу к свойству пользователя будет определяться что грузить, например, при $Post->property3 подключаться поля из таблицы пользователей. Если первый доступ к Post->property1 - то выберутся только main поля, если сперва Post->property1, а потом $Post->property3 то произойдет запрос с выборкой только присоединяемых полей, потому что они по умолчанию lazy...
    ps: А вообще я тебя с трудом понимаю :)
     
  12. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    У меня в __get() и засунуто. Но с той разницей, что в модели (в описании класса) нет ничего лишнего вроде addProperty.

    Ок, на примерах.
    PHP:
    1. <?
    2. $user = new User(3);
    3. $user->name = 'Вася';
    4. $user->save();
    Нет ничего сложного.
    [sql]update user set name = 'Вася' where id = 3[/sql]

    Вот тут сложность
    PHP:
    1. <?
    2. $user = new User(3);
    3. $user->name .= ' edit'; // это append строки!
    4. $user->save();
    Происходит
    [sql]select * from user where id = 3
    update user set name = 'Вася edit' where id = 3[/sql]

    Впрос был в том, как обойти "select *" и я остановлся на выборе полей, которые не text и blob:
    [sql]show fields from user
    select id, name, somefield from user where id = 3
    update user set name = 'Вася edit' where id = 3[/sql]

    Первый запрос получает поля. PHP выкидывает все поля с типами text или blob. Потом вставляем остальные в select. По вызову метода save() делаем update.

    P.S. По поводу моего:
    В питоне очень много магических методов. Например, делая
    Код (Text):
    1. MyObj == 2
    Питон вызывает метод MyObj.__eq__(). PHP такого лишён.

    Или ты не понимаешь саму формулировку мыслий? За мной есть косяк: не умею формулировать вопросы и сложно формулирую идеи. Надо учиться.
     
  13. kostyl

    kostyl Guest

    lexa
    ну этот пост уже и ежу понятен(я типа ёж :))...
    да фигово что нельзя сделать чтото типа UPDATE user SET name= (SELECT 'name' FROM user WHERE id = 3) + ' edit' WHERE id = 3