Book-Chinese-MasterPerlToday

 view release on metacpan or  search on metacpan

lib/Book/Chinese/MasterPerlToday/DBIx-Class.pod  view on Meta::CPAN

Row 组件 L<DBIx::Class::Row> 是必须的组件。它为 L<DBIx::Class::ResultSourceProxy> 里 add_columns 提供 register_column 等,并且当你调用 search->first, find, all 所得到的就是基于该组件的实例。

而 ResultSourceProxy::Table 组件 L<DBIx::Class::ResultSource::Table> 也是必须的组件。该组件提供了 __PACKAGE__->table("error"), (由它的父类 L<DBIx::Class::ResultSourceProxy> 提供) ->add_columns, ->set_primary_key 等功能ã...

当对性能要求比较高的时候,我们可以替换 Core 为某几个组件,如果出错再加回去。当你拥有一个完整的测试集的时候,增加和减少就会变得比较简单。

=item * 扩展组件

DBIx::Class 最常见的插件有两种,一种是 ResultSet 的插件(通过 use base 'DBIx::Class::ResultSet';),另一种就是作为组件。

ResultSet 的插件一般通过覆盖 L<DBIx::Class::ResultSet> 的函数(如我写的 L<DBIx::Class::ResultSet::Void>),或者另外提供某个函数。(还有些插件如 L<DBIx::Class::QueryLog> 就不详细介绍了)

另一种作为组件的插件更为常见。详细的参考 L<DBIx::Class::Manual::Component>,下面只做简单介绍。

编写组件一般都需要覆盖原有函数,请注意 load_components 的顺序,这里使用了 C<Class::C3> 来做一个依次调用。

  sub insert {
    my $self = shift;
    # Do stuff with $self, like set default values.
    return $self->next::method( @_ );
  }

常见的组件有 L<DBIx::Class::UTF8Columns>, L<DBIx::Class::UUIDColumns> 等。代码都是比较简单,可以查看源代码进行阅读。

=back

=head2 FAQ

=over 4

=item * 获取当个 row

    resultset('Errors')->search( { cond => 'bla' } )->first;
    resultset('Errors')->single( { cond => 'bla' } );

->first 与 ->single 不同之处在于 ->first 会产生 C<cursor>, 而 ->single 不会。所以 single 略微快一点。但是需要注意的几点是

=over 4

=item * single 里不能有属性

    ->single( { cond => 'bla' }, { order_by => 'rating' } ); # Wrong
    ->search( { cond => 'bla' }, { order_by => 'rating' } )->single; # Right

=item * single 只能返回一条记录

当 single 选调用的 SQL 返回多于一条数据时,后台会有警告。如果你确定的知道你要用 single 在多条数据里,可以使用 rows

    ->search( { cond => 'bla' }, { rows => 1 } )->single; # Right

=back

另一种获取方式是使用

    resultset('Errors')->search( { cond => 'bla' } )->slice(0);

它将使用 LIMIT/OFFSET 直接得到一条数据。

=item * 复杂的 search

建议阅读 L<DBIx::Class::Manual::Cookbook> 和 L<SQL::Abstract>

    resultset('XXX')->search( {
        requestor => 'inna',
        worker => ['nwiger', 'rcwe', 'sfz'],
        status => { '!=', 'completed' }
    } );
    # SQL:
    # FROM xxx WHERE
    #   ( requestor = ? ) AND ( status != ? )
    #   AND ( worker = ? OR worker = ? OR worker = ? )

    resultset('XXX')->search( {
        date_entered => { '>' => \["to_date(?, 'MM/DD/YYYY')", "11/26/2008"] },
        date_expires => { '<' => \"now()" }
    } );
    # SQL:
    # FROM xxx WHERE
    #   date_entered > "to_date(?, 'MM/DD/YYYY') AND date_expires < now()

    resultset('XXX')->search( {
        -or => [
            -and => [a => 1, b => 2],
            -or  => [c => 3, d => 4],
            e    => [-and => {-like => 'foo%'}, {-like => '%bar'} ]
        ],
    } );
    # SQL:
    # FROM xxx WHERE
    #   ( (    ( a = ? AND b = ? ) 
    #       OR ( c = ? OR d = ? ) 
    #       OR ( e LIKE ? AND e LIKE ? ) ) )

=item * as_query

如果你对所写的 ->search 不太确定,你可以使用 ->as_query 来 debug

  $schema->resultset('user')->search( {
    user_id => { 'IN', [1, 2] },
    -or => [
      last_visit => { '>', time() - 86400 },
      last_update => { '>', time() - 86400 },
    ]
  }, {
    columns => ['username'],
    rows    => 1,
  } )->as_query;

  [ '(SELECT me.username FROM user me 
     WHERE ( ( ( last_visit > ?
              OR last_update > ? )
        AND user_id IN ( ?, ? ) ) )
     LIMIT 1)',
    [ 'last_visit', 1242290843 ]
  ... ]

=back

=head2 资源

=over 4



( run in 0.579 second using v1.01-cache-2.11-cpan-5837b0d9d2c )