Зачем нужен ORM?
ORM = Объектно-реляционная проекция
Для сохранения объектов в базу, мы их должны
преобразовать в реляционную форму и наоборот
В нашем коде получается смесь двух совершенно
разных языков - SQL и Perl.
Это тупо неудобно!
my $message = $user->messages->find( $message_id );
DBIx::Class
Почему именно он?
Самый популярный
Большое количество плагинов
Есть связки с Catalyst и HTML::FormFu
Я це люблю™
Импорт структуры базы
perl -MDBIx::Class::Schema::Loader=dump_to_dir:/foo/bar -MMy::
Schema -e 'My::Schema->connection("dbi:Pg:...", ...)'
Основы основ
В DBIx::Class есть две основные сущности
ResultSet
Row
ResultSet - это структура для формирования запроса.
Если метод возвращает этот тип данных, то он не
полезет в базу!
Row - полученная из базы строка. К её столбцам можно
обратиться как $row->column_name
Расширение Row-объектов
package My::Schema::Users;
__PACKAGE__->table( 'users' );
__PACKAGE__->add_columns(qw(id first last patronymic));
sub initials {
my $self = shift;
return join ' ', $self->last, map { substr($_,0,1) . "."} ( $self->first,
$self->patronymic);
}
1;
say $user->first;
say $user->last;
say $user->fio;
Расширение ResultSet-объектов
package My::Schema::People;
__PACKAGE__->resultset_class( 'My::ResultSet::People' );
1;
package My::ResultSet::People;
sub young {
my $self = shift;
$self->search( {
age => { -between => [ 17, 20 ] }
} );
}
my @girls = $schema->resultset('People')->young->sexy-
>girls;
Начинаем работать
Получаем ResultSet:
my $rs = $schema->resultset('Название');
$rs->search( query, params )
$rs->slice(first, last)
и их комбинации:
$rs->search( { sex => 'f' } )->search( { age => 18 } )->slice(0,1)->first;
$rs->find( $id1, $id2, $id3 )
$rs->all
while ( my $row = $rs->next ) {}
$rs->count;
$rs->new( { name => 'Petya' } )
Начинаем работать (строки)
my @rows = $rs->all;
$row->id
$row->name
$row->name( 'Изя' )
$row->update
$row->delete
$row->insert
Отношения
package My::Schema::User;
__PACKAGE__->add_columns( qw(id name gender) );
__PACKAGE__->has_many( 'posts' => 'My::Schema::Posts', 'user_id' );
__PACKAGE__->belongs_to( gender => 'My::Schema::Genders' );
1;
...
say $user->gender->name; #male
say $user->posts->first->title; # Как размножаются ёжики?
$user->add_to_posts( { title => 'RE: Как размножаются ёжики' } );
$user->posts->find( $post_id );
$user->search_related('posts')->search_related('comments', { order_by =>
'date' } );
Prefetch
Нам нужно сэкономить на запросах
my $posts = $schema->resultset('Posts');
foreach my $row ($posts->all) {
say $post->forum->moderator->name;
}
Всего один запрос
my $posts = $schema->resultset('Posts')->search(undef,{
prefetch => {
forum => 'moderator'
}
});
foreach my $post ( $posts->all ) {
say $post->forum->moderator->name;
}
Paging
Самая частая задача!
Зачем её делать дважды?
$resultset->search( { rows => 50 } );
$resultset->page(2);
$resultset->pager (Data::Page);
Аггрегативные функции
$posts->get_column('rating')->max;
$users->count;
$users->get_column('age')->avg;
Inflate, Deflate
Мы получаем тип данных из базы и превращаем его в
красивый объект.
И наоборот
Например, мы можем прозрачно сохранять перловую
структуру в каком-то поле!!
man DBIx::Class::InflateColumn
Выходим из резервации
плагины
DBIx::Class::FrozenColumns
Прозрачно сохраняем дополнительные столбцы в
одном поле
$user->name; #этот столбец у нас лежит в базе
$user->has_some_useless_property; # а этого - нет
DBIx::Class::DynamicSubclass
В зависимости от какого-то флагового поля в базе,
может создавать объекты других типов.
Получаем записи из таблицы Animals, а они сразу bless-
ятся в кошечек и собачек.
DBIx::Class::CustomPrefetch*
Упрощение работы с несколькими СУБД. Аналог
prefetch, но между базами
Отладка и оптимизация
ORM - гавно
( как сказал один дядька с Highload )
Итак,
Убедитесь, что дело в базе
DBI_PROFILE=1 ./my_script.pl
DBI::Profile: 0.046747s 2.34% (39 calls) comments_test.pl
@ 2009-10-16 02:41:41
Если таки в базе
DBIС_TRACE=1 ./my_script.pl
DBI_PROFILE=2 ./my_script.pl
Найдите медленные запросы
man DBIx::Class::QueryLog
Тормоза в DBIx::Class
Красная пилюля.
Применять по крайней необходимости!
$rs->result_class('DBIx::Class::ResultClass::
HashRefInflator');
0 comments
Post a comment