Как выглядит Model если используешь DAO

Обсуждение документации. Переводы Cookbook и авторские рецепты.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

код который был выполнен средствами DAO

Код: Выделить всё

        
$db = Yii::app()->db;
        $film_table = Film::tableName();
        $sql = "SELECT * FROM {$film_table}
        LIMIT 1000";
        $command=$db->createCommand($sql);
        $rows = $command->queryAll();

        $filmCollection = new FilmCollection;

        foreach($rows as $row) {
            $film = new Film;
            $film->id = (int)$row['id'];
            $film->name_ru = $row['name_ru'];
            $film->name_en = $row['name_en'];
            $film->year = $row['year'];
            $film->director_id = (int)$row['director_id'];
            $film->country = $row['country'];
            $film->presents = $row['presents'];
            $film->desc = $row['desc'];
            $film->video_better = (int)$row['video_better'];
            $film->audio_better = (int)$row['audio_better'];
             
             $filmCollection->add($film);
        }
        return $filmCollection; 
и AR

Код: Выделить всё

        $criteria = new CDbCriteria;
        $criteria->limit = 1000;
        $films = films::model()->findAll($criteria);
 
Последний раз редактировалось pirrat 2009.12.18, 16:29, всего редактировалось 1 раз.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

Sam Dark писал(а):Хм… довольно странно выходит. Если сами запросы выходят одинаковые и на схему ничего не тратится, то чем кардинально отличается построение коллекции AR Yii от твоего варианта?
Я вот тоже хочу понять, сижу разбираюсь...
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

поэкспериментировав ,я нашел "затычку".

выполнение этой строки

Код: Выделить всё

if(property_exists($record,$name)) 
съедает более 400мс на 1000 записей

упростив метод populateRecord до вида

Код: Выделить всё

    public function populateRecord($attributes,$callAfterFind=true)
    {
        if($attributes!==false)
        {
            $record=$this->instantiate($attributes);
            $record->setScenario('update');            
            foreach($attributes as $name=>$value)
            {        
                $record->_attributes[$name]=$value;
            }

            return $record;
        }
        else
            return null;
    } 
я получил время исполнения около 300мс
Последний раз редактировалось pirrat 2009.12.18, 16:34, всего редактировалось 1 раз.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

поэкспериментировал с этой функцией.
написал такой метод

Код: Выделить всё

    public function setAttributes($model, $attributes)
    {
        foreach($attributes as $name => $value)
        {
            if(property_exists($model, $name))
                $model->$name = $value;
        }
    }  
а в методе где создается коллекция прописал так:

Код: Выделить всё

        foreach($rows as $row) {
            $film = new Film;
            self::setAttributes($film, $row);
            $filmCollection->add($film);
        } 
время исполнения увеличилось в 3 раза!

Поскольку я думаю не кто таких больших выборок не делает, думаю что не очень страшно, но имейте ввиду!

Info: у меня 20 полей. соответственно происходит 20000 вызовов этой функции...
Последний раз редактировалось pirrat 2009.12.18, 16:48, всего редактировалось 1 раз.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Как выглядит Model если используешь DAO

Сообщение samdark »

Хм… а что у нас в этом случае теряется? Может предложить патч в ядро? Кстати, это 1.1 был или 1.0?
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

1.1, но код метода и в 1.0 такой же...
Вопроса не понял...

патч ядра php? ))
ну можно мнение qiang послушать на этот счет...
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Как выглядит Model если используешь DAO

Сообщение samdark »

Вопрос в том, идентичен ли результат, и он не идентичен.

т.е. ты выкинул:
— получение метаданных.
— проверку на существование свойства и его заполнение.
— проверку на существование атрибута в метаданных.
— заполнение первичного ключа.
— всё, что связано с behaviour-ами.

В принципе, это довольно логично, если данные необходимо только вывести и не производить с ними никаких действий.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

ну выкидывал я это лишь для того чтобы сверить время выполнения 2 способов, не более того, и оно оказалось довольно близким (с учетом выборки метаданных и тд)...

вобщем ни чего страшного в таких результатах я не вижу, по скольку как я уже говорил что при моем тесте происходит 20000 вызовов функции property_exists.
хотя увеличение работы всего скрипта в 3-4 раза только из-за вызовов этой функции приводит в недоумение...

интереснее будет проверишь на выборке данных из нескольких таблиц через JOIN...
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Как выглядит Model если используешь DAO

Сообщение samdark »

Ну… не только. Выкинуты ведь были и многие другие вещи.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

блин, я уже сам запутался под конец рабочего дня.
ещё раз тестирую:

по умолчанию 1000мс
при убранных проверки на существования св-ва (функции property_exists) - 525 мс
если убрать все остальное кроме установке атрибута 250мс

в итоге вызов property_exists показал спад производительности в 2 раза.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Как выглядит Model если используешь DAO

Сообщение samdark »

Уже занятнее. Это самое всё, кроме установки, довольно полезное.

т.е. убираем property_exists() и появляется вопрос: что будет при сохранении несуществующего свойства?
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

я вот пытаюсь понять: если мы объявили в моделе свойство, то после выборке данных, значение будет установлен в свойство, а не в массив _attributes (по умолчанию).
и что же нам это даст?, ведь при обращении к св-вам модели у нас отрабатывает метод __get, который и так нам вернет значение св-ва из массива _attributes!

Посмотрел код, так и не смог понять смысла этой проверки, и почему нельзя просто все писать в массив _attributes...
Зы: что то совсем мы захламили топик не по теме)
iGrog
Сообщения: 35
Зарегистрирован: 2009.12.21, 20:59
Контактная информация:

Re: Как выглядит Model если используешь DAO

Сообщение iGrog »

А как в рамках теории чистого DAO будут выглядеть связанные сущности?
Допустим я хочу получить пост с информацией об авторе и с комментариями (естественно с авторами комментариев).
Таблички такие:

Posts: PostID, UserID, PostContent
Users: UserID, DisplayName
Comments: CommentID, PostID, UserID, CommentContent

В случае с активрекорд мы бы использовали ->with("xxx"), а тут как?
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

а тут так же как обычно вы делаете запрос в бд, только из полученных данных, создаете коллекцию объектов.

Код: Выделить всё

$post = PostManager::getPostWithComments($id);
 
 PostManager

Код: Выделить всё

public function getPostWithComments($id)
{
//получили данные поста и создали объект
$post = self::getPostById($id);
//получаем комменты
$commentCollection = self:: getCommentsForPost($id);
 $post->comments =$commentCollection;
return $post;
}

public function getCommentsForPost($id)
{
//получаем комменты с авторами
    $sql = 'SELECT c.id as c_id,c.text as c_text,u.id as u_id,u.name as u_name
        FROM comment c 
        Left JOIN user  u 
        ON (u.id=c.user_id)
        WHERE post_id=:Id';

     $db = Yii::app()->db;
     $command=$db->createCommand($sql);
         $command->bindParam(":Id", $id);
     $rows = $command->queryAll();

        $commentCollection = new CommentCollection;

        foreach($rows as $row) {
            $comment = new Comment;
            $comment->id = $row['c_id'];
            $comment->text = $row['c_text'];
            $user = new User;
            $user->id = $row['u_id'];
            $user->name =  $row['u_name'];
            $comment->author = $user;
            $commentCollection->add($film);
        }
        return $commentCollection;
}

public function getPostById($id)
{
    //получаем данные
    //....

    $post=new Post;
    //присваеваем свойствам значения.
    //....

    return $post;
}
 
часть работы (например заполнение полей моделей) можно автоматизировать, но общий смысл такой...
Последний раз редактировалось pirrat 2009.12.21, 23:29, всего редактировалось 3 раза.
iGrog
Сообщения: 35
Зарегистрирован: 2009.12.21, 20:59
Контактная информация:

Re: Как выглядит Model если используешь DAO

Сообщение iGrog »

Ну то есть вариант только одно - хардкодить имена методов вида getPostsWithCommentsWithUsersWithRating...
Мне не очень нравится...
Хотелось бы что-нибудь полегче АР, но по-удобнее такого хардкода
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

отрефакторил выше приведенный пример...
Да здесь много ручной работы,я об этом предупредил в начале.

Этот метод я приводил не чтоб сделать конкурента AR, а показать как более-менее грамотно работать с DAO: работа с объектами а не примитивными типами, разделение сущности, коллекции и фабрики и тд.

есть решения по автоматизации, как их приведу к работоспособности - выложу (хотя есть подозрения что в итоге опять выйдет что то типа AR).
SpiLLeR
Сообщения: 350
Зарегистрирован: 2009.09.17, 16:47
Откуда: Санкт-Петербург
Контактная информация:

Re: Как выглядит Model если используешь DAO

Сообщение SpiLLeR »

Именно к нему все и придет, только AR, еще пытается избавить нас от привязки к конкретной СУБД и содержит другие доп. функции, которые в принципе можно урезать и получить нечто среднее к чему возможно ты и придешь. Чем выше уровень абстракции, тем больше это AR :)
Предупрежден - значит вооружен.
devKP.ru
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как выглядит Model если используешь DAO

Сообщение pirrat »

Ну у меня не придет(просто не вижу смысла изобретать велосипед), поскольку я сам и так использую AR в своих проектах, за исключением мест где AR не позволяет без костылей реализовать нужный функционал...
Это решение было(за исключением некоторых нюансов, которые я уже сам дописал в этом топике) разработано нашей группой разработчиков(хотя это не совсем верно, поскольку по большей части это набор паттернов, описанных много где), для компании в которой я работаю и удачно применяется в боевых проектах, а от ORM cистем у нас отказались по некоторым соображениям.
Поэтому для меня такое решение "прозапас", когда по каким то причинам я не смогу использовать AR...
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Как выглядит Model если используешь DAO

Сообщение samdark »

Переработал труд pirrat и оформил в рецепт: http://yiiframework.ru/doc/cookbook/ru/model.dao
iGrog
Сообщения: 35
Зарегистрирован: 2009.12.21, 20:59
Контактная информация:

Re: Как выглядит Model если используешь DAO

Сообщение iGrog »

В качестве именно рецепта я бы не рассматривал эту статью.
Слишком много низкоуровневого и ручного кода:

- ручной SQL
- конструкции вида:

Код: Выделить всё

 $film = new Film;
 $film->id = $row['id'];
 $film->name_ru = $row['name_ru'];
- отсутствие гибкости с with. Там вообще пример с отдельным запросом

Код: Выделить всё

         //получаем комментарии для фильма
        $film->comments = CommentsManager::getCommentsForFilm($id);
когда можно было сразу с джойном выбрать все комменты.
Если последнее еще можно пережить, то первые два пункта - убивают
Для проекта большего чем homepage это явно не пойдет.

Давайте подумаем, как использовать DAO, но без такого жесткого хардкодинга.
Например пункт 2 можно заменить написав хелпер:

Код: Выделить всё

    public static function Assign($obj, $data)
    {
        $attr = $obj->attributeNames();
        foreach($data as $key=>$val)
        {
            if(in_array($key, $attr)) $obj->$key = $val;
        }
    }
и использовать:

Код: Выделить всё

        $film = new Film;
        Helper::Assign($file, $row);
От ручного SQL наверное тоже стоит избавиться если посмотреть в сторону CDbCommandBuilder.
А вот проблему с ->with("comments") пока не знаю.
Да и еще, как красиво работать с onBeforeSave, onAfterSave... приходится вызывать их ручками из слоя сервисов?

Код: Выделить всё

function AddFilm($film)
{
    $film->beforeSave();
   // generating insert query
   $film->afterSave();
}
Тоже как-то кривовато выглядит...
Но это так - мысли вслух, дабы коллективным разумом придти к более оптимальному решению.
Ответить