ktats****@users*****
ktats****@users*****
2011年 4月 29日 (金) 01:44:57 JST
Index: docs/modules/DBIx-Class-0.08127/lib/DBIx/Class/Manual/Component.pod diff -u /dev/null docs/modules/DBIx-Class-0.08127/lib/DBIx/Class/Manual/Component.pod:1.1 --- /dev/null Fri Apr 29 01:44:57 2011 +++ docs/modules/DBIx-Class-0.08127/lib/DBIx/Class/Manual/Component.pod Fri Apr 29 01:44:57 2011 @@ -0,0 +1,139 @@ + +=head1 NAME + +DBIx::Class::Manual::Component - Developing DBIx::Class Components + +=head1 WHAT IS A COMPONENT + +A component is a module that can be added in to your DBIx::Class +classes to provide extra functionality. A good example is the PK::Auto +component which automatically retrieves primary keys that the database +itself creates, after the insert has happened. + +=head1 USING + +Components are loaded using the load_components() method within your +DBIx::Class classes. + + package My::Thing; + use base qw( DBIx::Class::Core ); + __PACKAGE__->load_components(qw/InflateColumn::DateTime TimeStamp/); + +Generally you do not want to specify the full package name +of a component, instead take off the DBIx::Class:: part of +it and just include the rest. If you do want to load a +component outside of the normal namespace you can do so +by prepending the component name with a +. + + __PACKAGE__->load_components(qw/ +My::Component /); + +Once a component is loaded all of it's methods, or otherwise, +that it provides will be available in your class. + +The order in which is you load the components may be very +important, depending on the component. If you are not sure, +then read the docs for the components you are using and see +if they mention anything about the order in which you should +load them. + +=head1 CREATING COMPONENTS + +Making your own component is very easy. + + package DBIx::Class::MyComp; + use base qw(DBIx::Class); + # Create methods, accessors, load other components, etc. + 1; + +When a component is loaded it is included in the calling +class' inheritance chain using L<Class::C3>. As well as +providing custom utility methods, a component may also +override methods provided by other core components, like +L<DBIx::Class::Row> and others. For example, you +could override the insert and delete methods. + + sub insert { + my $self = shift; + # Do stuff with $self, like set default values. + return $self->next::method( @_ ); + } + + sub delete { + my $self = shift; + # Do stuff with $self. + return $self->next::method( @_ ); + } + +Now, the order that a component is loaded is very important. Components +that are loaded first are the first ones in the inheritance stack. So, if +you override insert() but the DBIx::Class::Row component is loaded first +then your insert() will never be called, since the DBIx::Class::Row insert() +will be called first. If you are unsure as to why a given method is not +being called try printing out the Class::C3 inheritance stack. + + print join ', ' => Class::C3::calculateMRO('YourClass::Name'); + +Check out the L<Class::C3> docs for more information about inheritance. + +=head1 EXISTING COMPONENTS + +=head2 Extra + +These components provide extra functionality beyond +basic functionality that you can't live without. + +L<DBIx::Class::CDBICompat> - Class::DBI Compatibility layer. + +L<DBIx::Class::FormTools> - Build forms with multiple interconnected objects. + +L<DBIx::Class::HTMLWidget> - Like FromForm but with DBIx::Class and HTML::Widget. + +L<DBIx::Class::Ordered> - Modify the position of objects in an ordered list. + +L<DBIx::Class::PK::Auto> - Retrieve automatically created primary keys upon insert. + +L<DBIx::Class::QueriesTime> - Display the amount of time it takes to run queries. + +L<DBIx::Class::RandomStringColumns> - Declare virtual columns that return random strings. + +L<DBIx::Class::UUIDColumns> - Implicit UUID columns. + +L<DBIx::Class::WebForm> - CRUD methods. + +=head2 Experimental + +These components are under development, their interfaces may +change, they may not work, etc. So, use them if you want, but +be warned. + +L<DBIx::Class::Validation> - Validate all data before submitting to your database. + +=head2 Core + +These are the components that all, or nearly all, people will use +without even knowing it. These components provide most of +DBIx::Class' functionality. + +L<DBIx::Class::Core> - Loads various components that "most people" would want. + +L<DBIx::Class::AccessorGroup> - Lets you build groups of accessors. + +L<DBIx::Class::DB> - Non-recommended classdata schema component. + +L<DBIx::Class::InflateColumn> - Automatically create objects from column data. + +L<DBIx::Class::PK> - This class contains methods for handling primary keys and methods depending on them. + +L<DBIx::Class::Relationship> - Inter-table relationships. + +L<DBIx::Class::ResultSourceProxy::Table> - Provides a classdata table object and method proxies. + +L<DBIx::Class::Row> - Basic row methods. + +=head1 SEE ALSO + +L<DBIx::Class::Manual::Cookbook> + +=head1 AUTHOR + +Aran Clary Deltac <bluef****@cpan*****> Index: docs/modules/DBIx-Class-0.08127/lib/DBIx/Class/Manual/Cookbook.pod diff -u /dev/null docs/modules/DBIx-Class-0.08127/lib/DBIx/Class/Manual/Cookbook.pod:1.1 --- /dev/null Fri Apr 29 01:44:57 2011 +++ docs/modules/DBIx-Class-0.08127/lib/DBIx/Class/Manual/Cookbook.pod Fri Apr 29 01:44:57 2011 @@ -0,0 +1,2618 @@ +=encoding utf8 + +=head1 åå + +DBIx::Class::Manual::Cookbook - ã¬ã·ããããã + +=head1 æ¤ç´¢ + +=head2 ãã¼ã¸å¦çãããçµæ + +=begin original + +When you expect a large number of results, you can ask L<DBIx::Class> for a +paged resultset, which will fetch only a defined number of records at a time: + +=end original + +çµæã»ãããè¨å¤§ã«ãªããããªãããã¼ã¸å¦çãããçµæãL<DBIx::Class>ã§åå¾ã§ãã¾ãã +ä¸åã«ã決ã¾ã£ãæ°ã®ã¬ã³ã¼ãããã¨ã£ã¦ãã¾ãã: + + my $rs = $schema->resultset('Artist')->search( + undef, + { + page => 1, # page to return (defaults to 1) + rows => 10, # number of results per page + }, + ); + + return $rs->all(); # all records for page 1 + + return $rs->page(2); # records for page 2 + +=begin original + +You can get a L<Data::Page> object for the resultset (suitable for use +in e.g. a template) using the C<pager> method: + +=end original + +ä¸ã®ã±ã¼ã¹ã®ãããã§ããçµæã»ããã«ãL<Data::Page>ãªãã¸ã§ã¯ã(ãã³ãã¬ã¼ãã«ä½¿ãã®ã«é©ãã) +ãå¾ããã¨ãã§ãã¾ããC<pager>ã¡ã½ããã使ã£ã¦: + + return $rs->pager(); + +=head2 è¤é㪠WHEREç¯ + +=begin original + +Sometimes you need to formulate a query using specific operators: + +=end original + +ç¹å®ã®æ¼ç®åã使ã£ãã¯ã¨ãªãå®å¼åããå¿ è¦ãããæãããã§ããã: + + my @albums = $schema->resultset('Album')->search({ + artist => { 'like', '%Lamb%' }, + title => { 'like', '%Fear of Fours%' }, + }); + +=begin original + +This results in something like the following C<WHERE> clause: + +=end original + +çµæã¯ä¸è¨ã®C<WHERE>ç¯ã®ãããªãã®ã«ãªãã¾ã: + + WHERE artist LIKE ? AND title LIKE ? + +=begin original + +And the following bind values for the placeholders: C<'%Lamb%'>, C<'%Fear of +Fours%'>. + +=end original + +ããã¦ããã¬ã¼ã¹ãã©ã«ãã¼ã®ããã«ããã¤ã³ãããå¤ãç¶ãã¾ã: C<%Lamb%>, C<'%Fear of +Fours%'>. + +=begin original + +Other queries might require slightly more complex logic: + +=end original + +ããã¡ãã£ã¨è¤éãªãã¸ãã¯ãå¿ è¦ãªä»ã®ã¯ã¨ãªãããã§ããã: + + my @albums = $schema->resultset('Album')->search({ + -or => [ + -and => [ + artist => { 'like', '%Smashing Pumpkins%' }, + title => 'Siamese Dream', + ], + artist => 'Starchildren', + ], + }); + +=begin original + +This results in the following C<WHERE> clause: + +=end original + +çµæã¯ä¸è¨ã®C<WHERE>ç¯ã«ãªãã¾ã: + + WHERE ( artist LIKE '%Smashing Pumpkins%' AND title = 'Siamese Dream' ) + OR artist = 'Starchildren' + +=begin original + +For more information on generating complex queries, see +L<SQL::Abstract/WHERE CLAUSES>. + +=end original + +è¤éãªã¯ã¨ãªãã¤ããããã®ãã詳ãã説æã¯ãL<SQL::Abstract/WHERE CLAUSES>ãè¦ã¦ãã ããã + +=head2 Retrieve one and only one row from a resultset + +Sometimes you need only the first "top" row of a resultset. While this +can be easily done with L<< $rs->first|DBIx::Class::ResultSet/first +>>, it is suboptimal, as a full blown cursor for the resultset will be +created and then immediately destroyed after fetching the first row +object. L<< $rs->single|DBIx::Class::ResultSet/single >> is designed +specifically for this case - it will grab the first returned result +without even instantiating a cursor. + +Before replacing all your calls to C<first()> with C<single()> please observe the +following CAVEATS: + +=over + +=item * + +While single() takes a search condition just like search() does, it does +_not_ accept search attributes. However one can always chain a single() to +a search(): + + my $top_cd = $cd_rs->search({}, { order_by => 'rating' })->single; + + +=item * + +Since single() is the engine behind find(), it is designed to fetch a +single row per database query. Thus a warning will be issued when the +underlying SELECT returns more than one row. Sometimes however this usage +is valid: i.e. we have an arbitrary number of cd's but only one of them is +at the top of the charts at any given time. If you know what you are doing, +you can silence the warning by explicitly limiting the resultset size: + + my $top_cd = $cd_rs->search ({}, { order_by => 'rating', rows => 1 })->single; + +=back + +=head2 Arbitrary SQL through a custom ResultSource + +Sometimes you have to run arbitrary SQL because your query is too complex +(e.g. it contains Unions, Sub-Selects, Stored Procedures, etc.) or has to +be optimized for your database in a special way, but you still want to +get the results as a L<DBIx::Class::ResultSet>. + +This is accomplished by defining a +L<ResultSource::View|DBIx::Class::ResultSource::View> for your query, +almost like you would define a regular ResultSource. + + package My::Schema::Result::UserFriendsComplex; + use strict; + use warnings; + use base qw/DBIx::Class::Core/; + + __PACKAGE__->table_class('DBIx::Class::ResultSource::View'); + + # ->table, ->add_columns, etc. + + # do not attempt to deploy() this view + __PACKAGE__->result_source_instance->is_virtual(1); + + __PACKAGE__->result_source_instance->view_definition(q[ + SELECT u.* FROM user u + INNER JOIN user_friends f ON u.id = f.user_id + WHERE f.friend_user_id = ? + UNION + SELECT u.* FROM user u + INNER JOIN user_friends f ON u.id = f.friend_user_id + WHERE f.user_id = ? + ]); + +Next, you can execute your complex query using bind parameters like this: + + my $friends = $schema->resultset( 'UserFriendsComplex' )->search( {}, + { + bind => [ 12345, 12345 ] + } + ); + +... and you'll get back a perfect L<DBIx::Class::ResultSet> (except, of course, +that you cannot modify the rows it contains, e.g. cannot call L</update>, +L</delete>, ... on it). + +Note that you cannot have bind parameters unless is_virtual is set to true. + +=over + +=item * NOTE + +If you're using the old deprecated C<< $rsrc_instance->name(\'( SELECT ...') >> +method for custom SQL execution, you are highly encouraged to update your code +to use a virtual view as above. If you do not want to change your code, and just +want to suppress the deprecation warning when you call +L<DBIx::Class::Schema/deploy>, add this line to your source definition, so that +C<deploy> will exclude this "table": + + sub sqlt_deploy_hook { $_[1]->schema->drop_table ($_[1]) } + +=back + +=head2 ç¹å®ã®ã«ã©ã ã使ã + +When you only want specific columns from a table, you can use +C<columns> to specify which ones you need. This is useful to avoid +loading columns with large amounts of data that you aren't about to +use anyway: + +ãã¼ãã«ããç¹å®ã®ã«ã©ã ã欲ããã ãã®ã¨ãã«ã¯ãC<columns>ã使ã£ã¦ã +å¿ è¦ãªãã®ãæå®ã§ãã¾ããä½ã«ã使ããªã大éã®ãã¼ã¿ãåãè¾¼ãã®ã +é¿ãããã¨ãã§ãã¾ãã + + my $rs = $schema->resultset('Artist')->search( + undef, + { + columns => [qw/ name /] + } + ); + + # Equivalent SQL: + # SELECT artist.name FROM artist + +This is a shortcut for C<select> and C<as>, see below. C<columns> +cannot be used together with C<select> and C<as>. + +å¾ã§ãè¦ã¾ãããããã¯ãC<select>ã¨C<as>ã®ã·ã§ã¼ãã«ããã§ãã +C<columns>ã¯C<select>ã¨C<as>ã¨ä¸ç·ã«ã¯ä½¿ãã¾ããã + +=head2 ãã¼ã¿ãã¼ã¹ã®é¢æ°ãã¹ãã¢ãããã·ã¼ã¸ã£ã使ã + +The combination of C<select> and C<as> can be used to return the result of a +database function or stored procedure as a column value. You use C<select> to +specify the source for your column value (e.g. a column name, function, or +stored procedure name). You then use C<as> to set the column name you will use +to access the returned value: + +C<select>ã¨C<as>ã®çµã¿åããã§ãã«ã©ã ã®å¤ã¨ãã¦ãã¼ã¿ãã¼ã¹é¢æ°ãã¹ãã¢ã +ããã·ã¼ã¸ã£ã®çµæãè¿ãã®ã«ä½¿ããã¨ãåºæ¥ã¾ããC<select>ã使ã£ã¦ãã«ã©ã ã® +å¤ã®ããã®ã½ã¼ã¹ãæå®ã§ãã¾ã(ä¾ãã°ãã«ã©ã åãé¢æ°ãã¹ãã¢ãããã·ã¼ã¸ã£å)ã +ãããããC<as>ããè¿ãããå¤ã«ã¢ã¯ã»ã¹ããã®ã«ä½¿ãã«ã©ã åãã»ããããã®ã« +使ãã¾ã: + + my $rs = $schema->resultset('Artist')->search( + {}, + { + select => [ 'name', { LENGTH => 'name' } ], + as => [qw/ name name_length /], + } + ); + + # Equivalent SQL: + # SELECT name name, LENGTH( name ) + # FROM artist + +Note that the C<as> attribute B<has absolutely nothing to do> with the SQL +syntax C< SELECT foo AS bar > (see the documentation in +L<DBIx::Class::ResultSet/ATTRIBUTES>). You can control the C<AS> part of the +generated SQL via the C<-as> field attribute as follows: + + my $rs = $schema->resultset('Artist')->search( + {}, + { + join => 'cds', + distinct => 1, + '+select' => [ { count => 'cds.cdid', -as => 'amount_of_cds' } ], + '+as' => [qw/num_cds/], + order_by => { -desc => 'amount_of_cds' }, + } + ); + + # Equivalent SQL + # SELECT me.artistid, me.name, me.rank, me.charfield, COUNT( cds.cdid ) AS amount_of_cds + # FROM artist me LEFT JOIN cd cds ON cds.artist = me.artistid + # GROUP BY me.artistid, me.name, me.rank, me.charfield + # ORDER BY amount_of_cds DESC + +If your alias exists as a column in your base class (i.e. it was added with +L<add_columns|DBIx::Class::ResultSource/add_columns>), you just access it as +normal. Our C<Artist> class has a C<name> column, so we just use the C<name> +accessor: + +C< as >å±æ§ã¯ãSQLã®ã·ã³ã¿ãã¯ã¹C< SELECT foo AS bar>ã¨ã¾ã£ããé¢ä¿ãªããã¨ã« +æ°ãã¤ãã¦ãã ãã(L<DBIx::Class::ResultSet/ATTRIBUTES>ã®ããã¥ã¡ã³ããè¦ã¦ãã ãã)ã +ãã¼ã¹ã¯ã©ã¹ã«ã«ã©ã ã¨ãã¦ã¨ã¤ãªã¢ã¹ããã(ããªãã¡ãC<add_columns>ã§è¿½å ããã¦ãã)ã®ãªãã +æ®éã«ããã«ã¢ã¯ã»ã¹ã§ãã¾ãããã®ä¾ã§è¨ãã°ãC<Artist>ã¯ã©ã¹ã«ã¯ã +C<name>ã«ã©ã ãããã®ã§ãC<name>ã¢ã¯ã»ãµã使ãã¾ã: + + my $artist = $rs->first(); + my $name = $artist->name(); + +If on the other hand the alias does not correspond to an existing column, you +have to fetch the value using the C<get_column> accessor: + +ä¸æ¹ã§ãã¨ã¤ãªã¢ã¹ãæ¢åã®ã«ã©ã ã«ä¸è´ããªããªããC<get_column>ã¢ã¯ã»ãµã使ã£ã¦ã +å¤ãåå¾ããå¿ è¦ãããã¾ã: + + my $name_length = $artist->get_column('name_length'); + +If you don't like using C<get_column>, you can always create an accessor for +any of your aliases using either of these: + +C<get_column>ãæ°ã«å ¥ããªããã°ããã¤ã§ããä¸è¨ã®ããããã使ã£ã¦ã©ã㪠+ã¨ã¤ãªã¢ã¹ã«ãã¢ã¯ã»ãµãä½ãã¾ã: + + # Define accessor manually: + sub name_length { shift->get_column('name_length'); } + + # Or use DBIx::Class::AccessorGroup: + __PACKAGE__->mk_group_accessors('column' => 'name_length'); + +See also L</Using SQL functions on the left hand side of a comparison>. + +=head2 SELECT DISTINCT with multiple columns + + my $rs = $schema->resultset('Artist')->search( + {}, + { + columns => [ qw/artist_id name rank/ ], + distinct => 1 + } + ); + + my $rs = $schema->resultset('Artist')->search( + {}, + { + columns => [ qw/artist_id name rank/ ], + group_by => [ qw/artist_id name rank/ ], + } + ); + + # Equivalent SQL: + # SELECT me.artist_id, me.name, me.rank + # FROM artist me + # GROUP BY artist_id, name, rank + +=head2 SELECT COUNT(DISTINCT colname) + + my $rs = $schema->resultset('Artist')->search( + {}, + { + columns => [ qw/name/ ], + distinct => 1 + } + ); + + my $rs = $schema->resultset('Artist')->search( + {}, + { + columns => [ qw/name/ ], + group_by => [ qw/name/ ], + } + ); + + my $count = $rs->count; + + # Equivalent SQL: + # SELECT COUNT( * ) FROM (SELECT me.name FROM artist me GROUP BY me.name) me: + +=head2 çµæã®ã°ã«ã¼ãã³ã° + +L<DBIx::Class> supports C<GROUP BY> as follows: + +L<DBIx::Class>ã¯C<GROUP BY>ããµãã¼ããã¾ã: + + my $rs = $schema->resultset('Artist')->search( + {}, + { + join => [qw/ cds /], + select => [ 'name', { count => 'cds.id' } ], + as => [qw/ name cd_count /], + group_by => [qw/ name /] + } + ); + + # Equivalent SQL: + # SELECT name, COUNT( cd.id ) FROM artist + # LEFT JOIN cd ON artist.id = cd.artist + # GROUP BY name + +Please see L<DBIx::Class::ResultSet/ATTRIBUTES> documentation if you +are in any way unsure about the use of the attributes above (C< join +>, C< select >, C< as > and C< group_by >). + +ä¸è¨ã®(C< join >ã C< select >ã C< as >ã C< group_by>)å±æ§ã®ä½¿ãæ¹ãããããªããã°ã +L<DBIx::Class::ResultSet/ATTRIBUTES>ããã¥ã¡ã³ããã¿ã¦ãã ããã + +=head2 Subqueries + +You can write subqueries relatively easily in DBIC. + + my $inside_rs = $schema->resultset('Artist')->search({ + name => [ 'Billy Joel', 'Brittany Spears' ], + }); + + my $rs = $schema->resultset('CD')->search({ + artist_id => { 'IN' => $inside_rs->get_column('id')->as_query }, + }); + +The usual operators ( =, !=, IN, NOT IN, etc.) are supported. + +B<NOTE>: You have to explicitly use '=' when doing an equality comparison. +The following will B<not> work: + + my $rs = $schema->resultset('CD')->search({ + artist_id => $inside_rs->get_column('id')->as_query, # does NOT work + }); + +=head3 Support + +Subqueries are supported in the where clause (first hashref), and in the +from, select, and +select attributes. + +=head3 Correlated subqueries + + my $cdrs = $schema->resultset('CD'); + my $rs = $cdrs->search({ + year => { + '=' => $cdrs->search( + { artist_id => { '=' => { -ident => 'me.artist_id' } } }, + { alias => 'inner' } + )->get_column('year')->max_rs->as_query, + }, + }); + +That creates the following SQL: + + SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track + FROM cd me + WHERE year = ( + SELECT MAX(inner.year) + FROM cd inner + WHERE artist_id = me.artist_id + ) + +=head2 å®ç¾©æ¸ã¿æ¤ç´¢ + +You can define frequently used searches as methods by subclassing +L<DBIx::Class::ResultSet>: + +L<DBIx::Class::ResultSet>ã¯ã©ã¹ãç¶æ¿ãã¦ãèªåèªèº«ã®ã¯ã©ã¹ãæ¸ãããã使ã +æ¤ç´¢ãã¡ã½ããã¨ãã¦å®ç¾©ã§ãã¾ã: + + package My::DBIC::ResultSet::CD; + use strict; + use warnings; + use base 'DBIx::Class::ResultSet'; + + sub search_cds_ordered { + my ($self) = @_; + + return $self->search( + {}, + { order_by => 'name DESC' }, + ); + } + + 1; + +If you're using L<DBIx::Class::Schema/load_namespaces>, simply place the file +into the C<ResultSet> directory next to your C<Result> directory, and it will +be automatically loaded. + +If however you are still using L<DBIx::Class::Schema/load_classes>, first tell +DBIx::Class to create an instance of the ResultSet class for you, in your +My::DBIC::Schema::CD class: + +èªåã®çµæã»ãã使ãã«ã¯ãæåã«ãèªåã®My::DBIC::Schema::CDã¯ã©ã¹ã®ä¸ã§ã +DBIx::Classã«ãã®ã¤ã³ã¹ã¿ã³ã¹ãä½ãããã«æãã¾ãã + + # class definition as normal + use base 'DBIx::Class::Core'; + __PACKAGE__->table('cd'); + + # tell DBIC to use the custom ResultSet class + __PACKAGE__->resultset_class('My::DBIC::ResultSet::CD'); + +Note that C<resultset_class> must be called after C<load_components> and C<table>, or you will get errors about missing methods. + +Then call your new method in your code: + +ãããããã³ã¼ãã®ä¸ã§ãæ°ããã¡ã½ãããå¼ã³ã¾ã: + + my $ordered_cds = $schema->resultset('CD')->search_cds_ordered(); + +=head2 Using SQL functions on the left hand side of a comparison + +Using SQL functions on the left hand side of a comparison is generally not a +good idea since it requires a scan of the entire table. (Unless your RDBMS +supports indexes on expressions - including return values of functions - and +you create an index on the return value of the function in question.) However, +it can be accomplished with C<DBIx::Class> when necessary by resorting to +literal SQL: + + $rs->search(\[ 'YEAR(date_of_birth) = ?', [ plain_value => 1979 ] ]); + + # Equivalent SQL: + # SELECT * FROM employee WHERE YEAR(date_of_birth) = ? + + $rs->search({ -and => [ + name => 'Bob', + \[ 'YEAR(date_of_birth) = ?', [ plain_value => 1979 ] ], + ]}); + + # Equivalent SQL: + # SELECT * FROM employee WHERE name = ? AND YEAR(date_of_birth) = ? + +Note: the C<plain_value> string in the C<< [ plain_value => 1979 ] >> part +should be either the same as the name of the column (do this if the type of the +return value of the function is the same as the type of the column) or in the +case of a function it's currently treated as a dummy string (it is a good idea +to use C<plain_value> or something similar to convey intent). The value is +currently only significant when handling special column types (BLOBs, arrays, +etc.), but this may change in the future. + +See also L<SQL::Abstract/Literal SQL with placeholders and bind values +(subqueries)>. + + +=head1 JOINS AND PREFETCHING + +=head2 joins 㨠prefetch ã使ã + +You can use the C<join> attribute to allow searching on, or sorting your +results by, one or more columns in a related table. + +C<join>å±æ§ã使ã£ã¦ãé¢é£ãããã¼ãã«ã®1ã¤ä»¥ä¸ã®ã«ã©ã ã使ã£ã¦ã +æ¤ç´¢ããçµæã®ã½ã¼ããã§ãã¾ãã + +This requires that you have defined the L<DBIx::Class::Relationship>. For example : + +L<DBIx::Class::Relationship>ãå®ç¾©ããå¿ è¦ãããã¾ããä¾ãã°: + + My::Schema::CD->has_many( artists => 'My::Schema::Artist', 'artist_id'); + +To return all CDs matching a particular artist name, you specify the name of the relationship ('artists'): + +ç¹å®ã®ã¢ã¼ãã£ã¹ãåã®å ¨ã¦ã®CDãè¿ãããã«ã¯: + + + my $rs = $schema->resultset('CD')->search( + { + 'artists.name' => 'Bob Marley' + }, + { + join => 'artists', # join the artist table + } + ); + + # Equivalent SQL: + # SELECT cd.* FROM cd + # JOIN artist ON cd.artist = artist.id + # WHERE artist.name = 'Bob Marley' + +In that example both the join, and the condition use the relationship name rather than the table name +(see L<DBIx::Class::Manual::Joining> for more details on aliasing ). + +If required, you can now sort on any column in the related tables by including +it in your C<order_by> attribute, (again using the aliased relation name rather than table name) : + +å¿ è¦ãªããC<order_by>å±æ§ã«ãããå«ãã¦ãé¢é£ãããã¼ãã«ã®ããããã®ã«ã©ã 㧠+ã½ã¼ããããã¨ãåºæ¥ã¾ã(ãã¼ãã«åã§ã¯ãªãã¨ã¤ãªã¢ã¹ã®ãªã¬ã¼ã·ã§ã³åãå度使ã£ã¦): + + my $rs = $schema->resultset('CD')->search( + { + 'artists.name' => 'Bob Marley' + }, + { + join => 'artists', + order_by => [qw/ artists.name /] + } + ); + + # Equivalent SQL: + # SELECT cd.* FROM cd + # JOIN artist ON cd.artist = artist.id + # WHERE artist.name = 'Bob Marley' + # ORDER BY artist.name + +Note that the C<join> attribute should only be used when you need to search or +sort using columns in a related table. Joining related tables when you only +need columns from the main table will make performance worse! + +C<join>å±æ§ã¯é¢é£ãããã¼ãã«ã®ã«ã©ã ã使ã£ã¦æ¤ç´¢ãã½ã¼ããããå¿ è¦ãããã¨ãã«ã®ã¿ +使ãããã¹ãã ã¨ãããã¨ã«æ³¨æãã¦ãã ããã +ã¡ã¤ã³ã®ãã¼ãã«ããã«ã©ã ãå¿ è¦ãªã¨ãã«ãé¢é£ãããã¼ãã«ãçµåããã®ã¯ã +ããã©ã¼ãã³ã¹ãæªãã§ã! + +Now let's say you want to display a list of CDs, each with the name of the +artist. The following will work fine: + +ã§ããCDã®ãªã¹ãããããããã®ã¢ã¼ãã£ã¹ãã®ååã¨ä¸ç·ã«è¡¨ç¤ºãããã¨ãã¾ãããã +ä¸è¨ã®ããããã§ãã¾ãããã¾ã: + + while (my $cd = $rs->next) { + print "CD: " . $cd->title . ", Artist: " . $cd->artist->name; + } + +There is a problem however. We have searched both the C<cd> and C<artist> tables +in our main query, but we have only returned data from the C<cd> table. To get +the artist name for any of the CD objects returned, L<DBIx::Class> will go back +to the database: + +ã§ãããä¸ã¤åé¡ãããã¾ãããã®ã¡ã¤ã³ã¯ã¨ãªã§ãC<cd>ã¨C<artist>ãã¼ãã«ã®ä¸¡æ¹ã +æ¤ç´¢ãã¦ãã¾ãããC<cd>ããã®ã¿ãã¼ã¿ãè¿ããã¦ãã¾ããè¿ãããCDãªãã¸ã§ã¯ãã®ä¸é¨ã§ã +ã¢ã¼ãã£ã¹ãåãå¾ãããã«ãL<DBIx::Class>ã¯ããã¼ã¿ãã¼ã¹ã«æ»ãã¾ã: + + SELECT artist.* FROM artist WHERE artist.id = ? + +A statement like the one above will run for each and every CD returned by our +main query. Five CDs, five extra queries. A hundred CDs, one hundred extra +queries! + +ä¸è¨ã®ãããªã¹ãã¼ãã¡ã³ãããã¡ã¤ã³ã¯ã¨ãªã«ãã£ã¦è¿ããããããããã®ãå ¨ã¦ã® +CDã§èµ°ãã¾ãã5ã¤ã®CDã§ããã°ã5ã¤ã®å¥ã®ã¯ã¨ãªã§ãã100ã®CDã§ããã°ã100ã®å¥ã® +ã¯ã¨ãª! + +Thankfully, L<DBIx::Class> has a C<prefetch> attribute to solve this problem. +This allows you to fetch results from related tables in advance: + +ããããããã¨ã«ãL<DBIx::Class>ã¯ãC<prefetch>å±æ§ãããããã®åé¡ã解決ã§ãã¾ãã +ãã®å±æ§ã使ãã¨ãå ã«é¢é£ãããã¼ãã«ããçµæãã¨ã£ã¦ããã¾ã: + + + my $rs = $schema->resultset('CD')->search( + { + 'artists.name' => 'Bob Marley' + }, + { + join => 'artists', + order_by => [qw/ artists.name /], + prefetch => 'artists' # return artist data too! + } + ); + + # Equivalent SQL (note SELECT from both "cd" and "artist"): + # SELECT cd.*, artist.* FROM cd + # JOIN artist ON cd.artist = artist.id + # WHERE artist.name = 'Bob Marley' + # ORDER BY artist.name + +The code to print the CD list remains the same: + +CDã®ãªã¹ãã表示ããã³ã¼ãã¯åãç©ã使ãã¾ã: + + while (my $cd = $rs->next) { + print "CD: " . $cd->title . ", Artist: " . $cd->artist->name; + } + +L<DBIx::Class> has now prefetched all matching data from the C<artist> table, +so no additional SQL statements are executed. You now have a much more +efficient query. + +L<DBIx::Class>ã¯C<artist>ãã¼ãã«ãããã¹ã¦ã®ããããããã¼ã¿ãå ã«ã¨ã£ã¦ãã¦ãã¾ãã +ãã®ãããä½åãªSQLã¹ãã¼ãã¡ã³ãã¯å®è¡ããã¾ãããããå¹ççãªã¯ã¨ãªã«ãªãã¾ããã + +Also note that C<prefetch> should only be used when you know you will +definitely use data from a related table. Pre-fetching related tables when you +only need columns from the main table will make performance worse! + +ã¾ããC<prefetch>ã¯ãé¢é£ãããã¼ãã«ãããã¼ã¿ãå¿ ã使ãã¨ããã£ã¦ããã¨ãã®ã¿ã«ã +使ãã¹ãã§ããã¡ã¤ã³ãã¼ãã«ããã®ã«ã©ã ããå¿ è¦ã¨ããªããªãã +é¢é£ãããã¼ãã«ããå ã«åå¾ããã®ã¯ãããã©ã¼ãã³ã¹ãæªããã¾ã! + +=head2 è¤æ°ã®çµå(join) + +In the examples above, the C<join> attribute was a scalar. If you +pass an array reference instead, you can join to multiple tables. In +this example, we want to limit the search further, using +C<LinerNotes>: + + # Relationships defined elsewhere: + # CD->belongs_to('artist' => 'Artist'); + # CD->has_one('liner_notes' => 'LinerNotes', 'cd'); + my $rs = $schema->resultset('CD')->search( + { + 'artist.name' => 'Bob Marley' + 'liner_notes.notes' => { 'like', '%some text%' }, + }, + { + join => [qw/ artist liner_notes /], + order_by => [qw/ artist.name /], + } + ); + + # Equivalent SQL: + # SELECT cd.*, artist.*, liner_notes.* FROM cd + # JOIN artist ON cd.artist = artist.id + # JOIN liner_notes ON cd.id = liner_notes.cd + # WHERE artist.name = 'Bob Marley' + # ORDER BY artist.name + +=head2 ãã«ãã¹ãããã®çµå(join) + +Sometimes you want to join more than one relationship deep. In this example, +we want to find all C<Artist> objects who have C<CD>s whose C<LinerNotes> +contain a specific string: + +2ã¤ä»¥ä¸ã®æ·±ããªã¬ã¼ã·ã§ã³ã·ããã§joinãããã¨ããããã§ãããã +ãã®ä¾ã§ã¯ãC<LinerNotes>ã«ç¹å®ã®æåãå«ã¾ããC<CD>ãæã£ã¦ããã +C<Artist>ãªãã¸ã§ã¯ããæ¢ãããã¨ãã¾ã: + + # Relationships defined elsewhere: + # Artist->has_many('cds' => 'CD', 'artist'); + # CD->has_one('liner_notes' => 'LinerNotes', 'cd'); + + my $rs = $schema->resultset('Artist')->search( + { + 'liner_notes.notes' => { 'like', '%some text%' }, + }, + { + join => { + 'cds' => 'liner_notes' + } + } + ); + + # Equivalent SQL: + # SELECT artist.* FROM artist + # LEFT JOIN cd ON artist.id = cd.artist + # LEFT JOIN liner_notes ON cd.id = liner_notes.cd + # WHERE liner_notes.notes LIKE '%some text%' + +Joins can be nested to an arbitrary level. So if we decide later that we +want to reduce the number of Artists returned based on who wrote the liner +notes: + +çµåã¯ä»»æã®ã¬ãã«ã§ãã¹ãã§ãã¾ããã§ãã®ã§ãå¾ãããã©ã¤ãã¼ãã¼ãã +誰ãæ¸ããããå ã«ãè¿ãããã¢ã¼ãã£ã¹ãã®æ°ãæ¸ããããã¨æ±ºããã¨ããã: + + # Relationship defined elsewhere: + # LinerNotes->belongs_to('author' => 'Person'); + + my $rs = $schema->resultset('Artist')->search( + { + 'liner_notes.notes' => { 'like', '%some text%' }, + 'author.name' => 'A. Writer' + }, + { + join => { + 'cds' => { + 'liner_notes' => 'author' + } + } + } + ); + + # Equivalent SQL: + # SELECT artist.* FROM artist + # LEFT JOIN cd ON artist.id = cd.artist + # LEFT JOIN liner_notes ON cd.id = liner_notes.cd + # LEFT JOIN author ON author.id = liner_notes.author + # WHERE liner_notes.notes LIKE '%some text%' + # AND author.name = 'A. Writer' + +=head2 ãã«ãã¹ãããã§è¤æ°ã®çµå + +With various combinations of array and hash references, you can join +tables in any combination you desire. For example, to join Artist to +CD and Concert, and join CD to LinerNotes: + + # Relationships defined elsewhere: + # Artist->has_many('concerts' => 'Concert', 'artist'); + + my $rs = $schema->resultset('Artist')->search( + { }, + { + join => [ + { + cds => 'liner_notes' + }, + 'concerts' + ], + } + ); + + # Equivalent SQL: + # SELECT artist.* FROM artist + # LEFT JOIN cd ON artist.id = cd.artist + # LEFT JOIN liner_notes ON cd.id = liner_notes.cd + # LEFT JOIN concert ON artist.id = concert.artist + +=head2 Multi-step prefetch + +C<prefetch> can be nested more than one relationship +deep using the same syntax as a multi-step join: + +C<prefetch>ã¯ããã«ãã¹ãããã®çµåã¨åãã·ã³ã¿ãã¯ã¹ã§ã +2ã¤ä»¥ä¸ã®æ·±ããªã¬ã¼ã·ã§ã³ã·ããã§ãã¹ãã§ãã¾ãã: + + my $rs = $schema->resultset('Tag')->search( + {}, + { + prefetch => { + cd => 'artist' + } + } + ); + + # Equivalent SQL: + # SELECT tag.*, cd.*, artist.* FROM tag + # JOIN cd ON tag.cd = cd.id + # JOIN artist ON cd.artist = artist.id + +Now accessing our C<cd> and C<artist> relationships does not need additional +SQL statements: + + +ããã§ãC<cd>ã¨C<artist>ã®ãªã¬ã¼ã·ã§ã³ã·ããã«ã¢ã¯ã»ã¹ããã®ã«ã +追å ã®SQLã¹ãã¼ãã¡ã³ãã¯å¿ è¦ããã¾ãã: + + my $tag = $rs->first; + print $tag->cd->artist->name; + +=head1 ROW-LEVEL OPERATIONS + +=head2 åãªãã¸ã§ã¯ãã®ã¹ãã¼ããå¾ã + +It is possible to get a Schema object from a row object like so: + +次ã®ããã«ãã¦ãåã®ãªãã¸ã§ã¯ãããã¹ãã¼ããå¾ããã¨ãã§ãã¾ã: + + my $schema = $cd->result_source->schema; + # use the schema as normal: + my $artist_rs = $schema->resultset('Artist'); + +This can be useful when you don't want to pass around a Schema object to every +method. + +å ¨ã¦ã®ã¡ã½ããã§ãã¹ãã¼ããªãã¸ã§ã¯ããé ã«åããããªããã°ã便å©ã§ãããã + +=head2 æå¾ã«ãã¼ã¿ãã¼ã¹ã«ã¤ã³ãµã¼ããããã©ã¤ããªãã¼ã®å¤ãåããã + +AKA getting last_insert_id + +last_insert_id ãåãã¨ãããã¾ãã + +Thanks to the core component PK::Auto, this is straightforward: + +ã³ã¢ã³ã³ãã¼ãã³ãã®PK::Autoã«æè¬ãã¦ãç´æ¥: + + my $foo = $rs->create(\%blah); + # do more stuff + my $id = $foo->id; # foo->my_primary_key_field will also work. + +If you are not using autoincrementing primary keys, this will probably +not work, but then you already know the value of the last primary key anyway. + +ãªã¼ãã¤ã³ã¯ãªã¡ã³ãã®ãã©ã¤ããªãã¼ã使ã£ã¦ããªãã®ãªããããããåãã¾ããã +ã§ããããã®å ´åã¯ããã§ã«ããã©ã¤ããªãã¼ã®å¤ãç¥ã£ã¦ãããã¨ã§ãããã + +=head2 Stringification + +Employ the standard stringification technique by using the L<overload> +module. + +C<overload> ã¢ã¸ã¥ã¼ã«ã§æ¨æºçãªæåååã®ãã¯ããã¯ã使ãã¾ãã + +To make an object stringify itself as a single column, use something +like this (replace C<name> with the column/method of your choice): + +ã²ã¨ã¤ã®ã«ã©ã ã«ã¤ãã¦ããªãã¸ã§ã¯ãèªèº«ãæåååããã«ã¯ã +次ã®ããã«ãã¾ãã(ã«ã©ã /ã¡ã½ããã§C<name>ãç½®ãæãã¦ãã ãã) + + use overload '""' => sub { shift->name}, fallback => 1; + +For more complex stringification, you can use an anonymous subroutine: + +ããè¤éãªæåååã§ã¯ãç¡åãµãã«ã¼ãã³ã使ãã¾ã: + + use overload '""' => sub { $_[0]->name . ", " . + $_[0]->address }, fallback => 1; + +=head3 æåååã®ä¾ + +Suppose we have two tables: C<Product> and C<Category>. The table +specifications are: + +äºã¤ã®ãã¼ãã«ãããã¨ãã¾ã:C<Product>ã¨C<Cateogry>ã +ãã¼ãã«ã®å®ç¾©ã¯æ¬¡ã®éã: + + Product(id, Description, category) + Category(id, Description) + +C<category> is a foreign key into the Category table. + +C<category>ã¯Categoryãã¼ãã«ã®å¤é¨ãã¼ã§ãã + +If you have a Product object C<$obj> and write something like + +Productãªãã¸ã§ã¯ãC<$obj>ãããã次ã®ããã«æ¸ããã¨ããã¨ã + + print $obj->category + +things will not work as expected. + +æå¾ ã©ããã«ã¯åãã¾ããã + +To obtain, for example, the category description, you should add this +method to the class defining the Category table: + +ã«ãã´ãªã®å 容ãå¾ãããªããä¾ãã°ãCategoryãã¼ãã«ã®ã¯ã©ã¹å®ç¾©ã«æ¬¡ã® +ã¡ã½ããã追å ãã¹ãã§ã: + + use overload "" => sub { + my $self = shift; + + return $self->Description; + }, fallback => 1; + +=head2 find_or_create ãè¦ä»ããã®ããåãä½ã£ãã®ããç¥ãããï¼ + +Just use C<find_or_new> instead, then check C<in_storage>: + +C<find_or_new>ã代ããã«ä½¿ã£ã¦ãã ããããããããC<in_storage>ããã§ãã¯ãã¾ã: + + my $obj = $rs->find_or_new({ blah => 'blarg' }); + unless ($obj->in_storage) { + $obj->insert; + # do whatever else you wanted if it was a new row + } + +=head2 Static sub-classing DBIx::Class result classes + +AKA adding additional relationships/methods/etc. to a model for a +specific usage of the (shared) model. + +B<Schema definition> + + package My::App::Schema; + + use base 'DBIx::Class::Schema'; + + # load subclassed classes from My::App::Schema::Result/ResultSet + __PACKAGE__->load_namespaces; + + # load classes from shared model + load_classes({ + 'My::Shared::Model::Result' => [qw/ + Foo + Bar + /]}); + + 1; + +B<Result-Subclass definition> + + package My::App::Schema::Result::Baz; + + use strict; + use warnings; + use base 'My::Shared::Model::Result::Baz'; + + # WARNING: Make sure you call table() again in your subclass, + # otherwise DBIx::Class::ResultSourceProxy::Table will not be called + # and the class name is not correctly registered as a source + __PACKAGE__->table('baz'); + + sub additional_method { + return "I'm an additional method only needed by this app"; + } + + 1; + +=head2 DBIx::Classã®ãããã·ã¯ã©ã¹ãåçã«ãµãã¯ã©ã¹åãã + +AKA multi-class object inflation from one table + +AKA 1ã¤ã®ãã¼ãã«ãããã«ãã¯ã©ã¹ã®ãªãã¸ã§ã¯ãã«å±éãã + +L<DBIx::Class> classes are proxy classes, therefore some different +techniques need to be employed for more than basic subclassing. In +this example we have a single user table that carries a boolean bit +for admin. We would like like to give the admin users +objects (L<DBIx::Class::Row>) the same methods as a regular user but +also special admin only methods. It doesn't make sense to create two +separate proxy-class files for this. We would be copying all the user +methods into the Admin class. There is a cleaner way to accomplish +this. + +L<DBIx::Class>ã¯ã©ã¹ã¯ãããã·ã¯ã©ã¹ã§ãããã®ãããåºæ¬çãªãµãã¯ã©ã¹å以ä¸ã«ã +ããã¤ãã®éã£ããã¯ããã¯ãå¿ è¦ã¨ããã¾ãã +ãã®ä¾ã§ã¯ã管çè ç¨ã«çå½å¤ãæã£ã¦ããã¦ã¼ã¶ã¼ãã¼ãã«ãããã¾ãã +管çè ã¦ã¼ã¶ã¼ã«ã¯ããªãã¸ã§ã¯ã(L<DBIx::Class::Row>)ã®ã¡ã½ãããã +æ®éã®ã¦ã¼ã¶ã¼ã¨åãããã«ãããã¾ããã管çè ã®ã¿ã®ç¹å¥ãªã¡ã½ãããã +ãããããã¨ãã¾ãããã®ããã«2ã¤ã®ãããã·ã¯ã©ã¹ãã¡ã¤ã«ã«åå²ããã®ã¯ +çã«ããªãã¾ãããAdminã¯ã©ã¹ã«å ¨ã¦ã®ã¦ã¼ã¶ã¼ã¯ã©ã¹ã®ã¡ã½ãããã³ãã¼ +ãããã¨ã«ãªãã¾ãããããããããã«ããããã£ããããæ¹æ³ãããã¾ãã + +Overriding the C<inflate_result> method within the User proxy-class +gives us the effect we want. This method is called by +L<DBIx::Class::ResultSet> when inflating a result from storage. So we +grab the object being returned, inspect the values we are looking for, +bless it if it's an admin object, and then return it. See the example +below: + +ã¦ã¼ã¶ã¼ã®ãããã·ã¯ã©ã¹å ã§C<inflate_result>ã¡ã½ããããªã¼ãã¼ã©ã¤ããããã¨ã§ã +æãã§ããå¹æãå¾ããã¾ãããã®ã¡ã½ããã¯ãã¹ãã¬ã¼ã¸ããçµæãå±éãããã¨ãã«ã +L<DBIx::Class::ResultSet>ã«ãã£ã¦å¼ã°ãã¾ãã +è¿ããããªãã¸ã§ã¯ããæ´ãã ããæ¢ãã¦ããå¤ã調ã¹ã管çè ãªãã¸ã§ã¯ãã§ããã°ã +ãããblessãã¦è¿ãã¾ããä¸ã®ä¾ãè¦ã¦ãã ãã: + +B<Schema Definition> + + package My::Schema; + + use base qw/DBIx::Class::Schema/; + + __PACKAGE__->load_namespaces; + + 1; + + +B<Proxy-Class definitions> + + package My::Schema::Result::User; + + use strict; + use warnings; + use base qw/DBIx::Class::Core/; + + ### Define what our admin class is, for ensure_class_loaded() + my $admin_class = __PACKAGE__ . '::Admin'; + + __PACKAGE__->table('users'); + + __PACKAGE__->add_columns(qw/user_id email password + firstname lastname active + admin/); + + __PACKAGE__->set_primary_key('user_id'); + + sub inflate_result { + my $self = shift; + my $ret = $self->next::method(@_); + if( $ret->admin ) {### If this is an admin, rebless for extra functions + $self->ensure_class_loaded( $admin_class ); + bless $ret, $admin_class; + } + return $ret; + } + + sub hello { + print "I am a regular user.\n"; + return ; + } + + 1; + + + package My::Schema::Result::User::Admin; + + use strict; + use warnings; + use base qw/My::Schema::Result::User/; + + # This line is important + __PACKAGE__->table('users'); + + sub hello + { + print "I am an admin.\n"; + return; + } + + sub do_admin_stuff + { + print "I am doing admin stuff\n"; + return ; + } + + 1; + +B<Test File> test.pl + + use warnings; + use strict; + use My::Schema; + + my $user_data = { email => 'someg****@place*****', + password => 'pass1', + admin => 0 }; + + my $admin_data = { email => 'somea****@admin*****', + password => 'pass2', + admin => 1 }; + + my $schema = My::Schema->connection('dbi:Pg:dbname=test'); + + $schema->resultset('User')->create( $user_data ); + $schema->resultset('User')->create( $admin_data ); + + ### Now we search for them + my $user = $schema->resultset('User')->single( $user_data ); + my $admin = $schema->resultset('User')->single( $admin_data ); + + print ref $user, "\n"; + print ref $admin, "\n"; + + print $user->password , "\n"; # pass1 + print $admin->password , "\n";# pass2; inherited from User + print $user->hello , "\n";# I am a regular user. + print $admin->hello, "\n";# I am an admin. + + ### The statement below will NOT print + print "I can do admin stuff\n" if $user->can('do_admin_stuff'); + ### The statement below will print + print "I can do admin stuff\n" if $admin->can('do_admin_stuff'); + +Alternatively you can use L<DBIx::Class::DynamicSubclass> that implements +exactly the above functionality. + +=head2 é«éã«çµæãå¾ãããã«ããªãã¸ã§ã¯ãã®ä½æãã¹ãããããã + +DBIx::Class is not built for speed, it's built for convenience and +ease of use, but sometimes you just need to get the data, and skip the +fancy objects. + +DBIx::Class ã¯ã¹ãã¼ãã®ããã«ã¯ä½ããã¦ããããDBIx::Classã¯ã +å©ä¾¿æ§ã¨ä½¿ãæãã®ããã«ä½ããã¾ãããã§ãããæã«ã¯ããã¼ã¿ããã +åå¾ããªããã°ãããªãã ãã®æããããç´ æµãªãªãã¸ã§ã¯ãã¯ã¹ããã +ãããå ´åãããã§ãããã + +To do this simply use L<DBIx::Class::ResultClass::HashRefInflator>. + +ãã®ç¨éã«ã¯ãL<DBIx::Class::ResultClass::HashRefInflator>ããç°¡åã«ä½¿ãã¾ãã + + my $rs = $schema->resultset('CD'); + + $rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + + my $hash_ref = $rs->find(1); + +Wasn't that easy? + +Beware, changing the Result class using +L<DBIx::Class::ResultSet/result_class> will replace any existing class +completely including any special components loaded using +load_components, eg L<DBIx::Class::InflateColumn::DateTime>. + +=head2 Get raw data for blindingly fast results + +If the L<HashRefInflator|DBIx::Class::ResultClass::HashRefInflator> solution +above is not fast enough for you, you can use a DBIx::Class to return values +exactly as they come out of the database with none of the convenience methods +wrapped round them. + +This is used like so: + + my $cursor = $rs->cursor + while (my @vals = $cursor->next) { + # use $val[0..n] here + } + +You will need to map the array offsets to particular columns (you can +use the L<DBIx::Class::ResultSet/select> attribute of L<DBIx::Class::ResultSet/search> to force ordering). + +=head1 RESULTSET OPERATIONS + +=head2 Getting Schema from a ResultSet + +To get the L<DBIx::Class::Schema> object from a ResultSet, do the following: + + $rs->result_source->schema + +=head2 Getting Columns Of Data + +AKA Aggregating Data + +If you want to find the sum of a particular column there are several +ways, the obvious one is to use search: + +ç¹å®ã®ã«ã©ã ã®åè¨ãæ¢ããããã°ãããã¤ãã®æ¹æ³ãããã¾ããèªæã®ãã®ã¨ãã¦ã¯ã +searchã使ããã®ã§ã: + + my $rs = $schema->resultset('Items')->search( + {}, + { + select => [ { sum => 'Cost' } ], + as => [ 'total_cost' ], # remember this 'as' is for DBIx::Class::ResultSet not SQL + } + ); + my $tc = $rs->first->get_column('total_cost'); + +Or, you can use the L<DBIx::Class::ResultSetColumn>, which gets +returned when you ask the C<ResultSet> for a column using +C<get_column>: + +ãããã¯ãL<DBIx::Class::ResultSetColumn>ã使ããã¨ãåºæ¥ã¾ãã +ããã¯ãC<ResultSet>ã§C<get_column>ã使ã£ã¦ã«ã©ã ãåãã¨ãã« +è¿ããããã®ãåãã¾ãã + + my $cost = $schema->resultset('Items')->get_column('Cost'); + my $tc = $cost->sum; + +With this you can also do: + +ãããã次ã®ããã«ã§ãã¾ã: + + my $minvalue = $cost->min; + my $maxvalue = $cost->max; + +Or just iterate through the values of this column only: + +ã¾ãã¯ããã®ã«ã©ã ã®å¤ã®ã¿ãéãã¦ã¤ãã¬ã¼ããã¾ã: + + while ( my $c = $cost->next ) { + print $c; + } + + foreach my $c ($cost->all) { + print $c; + } + +C<ResultSetColumn> only has a limited number of built-in functions. If +you need one that it doesn't have, then you can use the C<func> method +instead: + +C<ResultSetColumn>ã¯å°ãã ããã«ãã¤ã³ã®é¢æ°ãããã¾ãã +ããã«ãªããã®ãå¿ è¦ãªããC<func>ã¡ã½ããã代ããã«ä½¿ããã¨ãã§ãã¾ã: + + my $avg = $cost->func('AVERAGE'); + +This will cause the following SQL statement to be run: + +ããããã¨ãä¸è¨ã®SQLã¹ãã¼ãã¡ã³ããèµ°ãã¾ã: + + SELECT AVERAGE(Cost) FROM Items me + +Which will of course only work if your database supports this function. +See L<DBIx::Class::ResultSetColumn> for more documentation. + +ãã¡ããã使ã£ã¦ãããã¼ã¿ãã¼ã¹ããã®é¢æ°ããµãã¼ããã¦ããªããã°ããã¾ããã +ãã詳ããã¯ãL<DBIx::Class::ResultSetColumn>ãã¿ã¦ãã ããã + +=head2 Creating a result set from a set of rows + +Sometimes you have a (set of) row objects that you want to put into a +resultset without the need to hit the DB again. You can do that by using the +L<set_cache|DBIx::Class::Resultset/set_cache> method: + + my @uploadable_groups; + while (my $group = $groups->next) { + if ($group->can_upload($self)) { + push @uploadable_groups, $group; + } + } + my $new_rs = $self->result_source->resultset; + $new_rs->set_cache(\@uploadable_groups); + return $new_rs; + +=head1 ãªã¬ã¼ã·ã§ã³ã·ããã使ã + +=head2 é¢é£ãããã¼ãã«ã«æ°ããåãä½ã + + my $author = $book->create_related('author', { name => 'Fred'}); + +=head2 é¢é£ãããã¼ãã«ãæ¤ç´¢ãã + +Only searches for books named 'Titanic' by the author in $author. + +$autorã®èè ã§ã'Titanic'ã¨ããååã®æ¬ã ããæ¤ç´¢ãããã + + my $books_rs = $author->search_related('books', { name => 'Titanic' }); + +=head2 é¢é£ãããã¼ãã«ã®ãã¼ã¿ãåé¤ãã + +Deletes only the book named Titanic by the author in $author. + +$autorã®èè ã§ãTitanicã¨ããååã®æ¬ã ããåé¤ãããã + + $author->delete_related('books', { name => 'Titanic' }); + +=head2 é¢ä¿ããçµæã»ããã®é åºä»ã + +If you always want a relation to be ordered, you can specify this when you +create the relationship. + +é åºä»ããããé¢ä¿ã常ã«ã»ãããªãããªã¬ã¼ã·ã§ã³ã·ãããä½ãã¨ãã«ã次ã®æå®ãã§ãã¾ãã + +To order C<< $book->pages >> by descending page_number, create the relation +as follows: + +page_numberãéé ã§ãC<< $book->pages >>ã並ã³å¤ããããªãã次ã®ããã« +ãªã¬ã¼ã·ã§ã³ãä½ãã¾ã: + + + __PACKAGE__->has_many('pages' => 'Page', 'book', { order_by => { -desc => 'page_number'} } ); + +=head2 Filtering a relationship result set + +If you want to get a filtered result set, you can just add add to $attr as follows: + + __PACKAGE__->has_many('pages' => 'Page', 'book', { where => { scrap => 0 } } ); + +=head2 Many-to-many ã®ãªã¬ã¼ã·ã§ã³ã·ãã + +This is straightforward using L<ManyToMany|DBIx::Class::Relationship/many_to_many>: + +ããã¯ãåç´ã«L<ManyToMany|DBIx::Class::Relationship/many_to_many>ã使ãã¾ã: + + package My::User; + use base 'DBIx::Class::Core'; + __PACKAGE__->table('user'); + __PACKAGE__->add_columns(qw/id name/); + __PACKAGE__->set_primary_key('id'); + __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'user'); + __PACKAGE__->many_to_many('addresses' => 'user_address', 'address'); + + package My::UserAddress; + use base 'DBIx::Class::Core'; + __PACKAGE__->table('user_address'); + __PACKAGE__->add_columns(qw/user address/); + __PACKAGE__->set_primary_key(qw/user address/); + __PACKAGE__->belongs_to('user' => 'My::User'); + __PACKAGE__->belongs_to('address' => 'My::Address'); + + package My::Address; + use base 'DBIx::Class::Core'; + __PACKAGE__->table('address'); + __PACKAGE__->add_columns(qw/id street town area_code country/); + __PACKAGE__->set_primary_key('id'); + __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'address'); + __PACKAGE__->many_to_many('users' => 'user_address', 'user'); + + $rs = $user->addresses(); # get all addresses for a user + $rs = $address->users(); # get all users for an address + + my $address = $user->add_to_addresses( # returns a My::Address instance, + # NOT a My::UserAddress instance! + { + country => 'United Kingdom', + area_code => 'XYZ', + town => 'London', + street => 'Sesame', + } + ); + +=head2 Relationships across DB schemas + +Mapping relationships across L<DB schemas|DBIx::Class::Manual::Glossary/DB schema> +is easy as long as the schemas themselves are all accessible via the same DBI +connection. In most cases, this means that they are on the same database host +as each other and your connecting database user has the proper permissions to them. + +To accomplish this one only needs to specify the DB schema name in the table +declaration, like so... + + package MyDatabase::Main::Artist; + use base qw/DBIx::Class::Core/; + + __PACKAGE__->table('database1.artist'); # will use "database1.artist" in FROM clause + + __PACKAGE__->add_columns(qw/ artist_id name /); + __PACKAGE__->set_primary_key('artist_id'); + __PACKAGE__->has_many('cds' => 'MyDatabase::Main::Cd'); + + 1; + +Whatever string you specify there will be used to build the "FROM" clause in SQL +queries. + +The big drawback to this is you now have DB schema names hardcoded in your +class files. This becomes especially troublesome if you have multiple instances +of your application to support a change lifecycle (e.g. DEV, TEST, PROD) and +the DB schemas are named based on the environment (e.g. database1_dev). + +However, one can dynamically "map" to the proper DB schema by overriding the +L<connection|DBIx::Class::Schama/connection> method in your Schema class and +building a renaming facility, like so: + + package MyDatabase::Schema; + use Moose; + + extends 'DBIx::Class::Schema'; + + around connection => sub { + my ( $inner, $self, $dsn, $username, $pass, $attr ) = ( shift, @_ ); + + my $postfix = delete $attr->{schema_name_postfix}; + + $inner->(@_); + + if ( $postfix ) { + $self->append_db_name($postfix); + } + }; + + sub append_db_name { + my ( $self, $postfix ) = @_; + + my @sources_with_db + = grep + { $_->name =~ /^\w+\./mx } + map + { $self->source($_) } + $self->sources; + + foreach my $source (@sources_with_db) { + my $name = $source->name; + $name =~ s{^(\w+)\.}{${1}${postfix}\.}mx; + + $source->name($name); + } + } + + 1; + +By overridding the L<connection|DBIx::Class::Schama/connection> +method and extracting a custom option from the provided \%attr hashref one can +then simply iterate over all the Schema's ResultSources, renaming them as +needed. + +To use this facility, simply add or modify the \%attr hashref that is passed to +L<connection|DBIx::Class::Schama/connect>, as follows: + + my $schema + = MyDatabase::Schema->connect( + $dsn, + $user, + $pass, + { + schema_name_postfix => '_dev' + # ... Other options as desired ... + }) + +Obviously, one could accomplish even more advanced mapping via a hash map or a +callback routine. + +=head1 txn_do ã§ã®ãã©ã³ã¶ã¯ã·ã§ã³ + +As of version 0.04001, there is improved transaction support in +L<DBIx::Class::Storage> and L<DBIx::Class::Schema>. Here is an +example of the recommended way to use it: + +0.04001以éã«ã L<DBIx::Class::Storage::DBI>ã¨L<DBIx::Class::Schema>ã«ãæ¹è¯ããã +ãã©ã³ã¶ã¯ã·ã§ã³ãµãã¼ããããã¾ããããã使ãæ¨å¥¨ãããæ¹æ³ã®ä¸ä¾ã§ã: + + my $genus = $schema->resultset('Genus')->find(12); + + my $coderef2 = sub { + $genus->extinct(1); + $genus->update; + }; + + my $coderef1 = sub { + $genus->add_to_species({ name => 'troglodyte' }); + $genus->wings(2); + $genus->update; + $schema->txn_do($coderef2); # Can have a nested transaction. Only the outer will actualy commit + return $genus->species; + }; + + use Try::Tiny; + my $rs; + try { + $rs = $schema->txn_do($coderef1); + } catch { + # Transaction failed + die "the sky is falling!" # + if ($_ =~ /Rollback failed/); # Rollback failed + + deal_with_failed_transaction(); + }; + +Note: by default C<txn_do> will re-run the coderef one more time if an +error occurs due to client disconnection (e.g. the server is bounced). +You need to make sure that your coderef can be invoked multiple times +without terrible side effects. + +Nested transactions will work as expected. That is, only the outermost +transaction will actually issue a commit to the $dbh, and a rollback +at any level of any transaction will cause the entire nested +transaction to fail. + +ãã¹ãããããã©ã³ã¶ã¯ã·ã§ã³ã¯æå¾ ã©ããã«åãã¾ãã +ä¸çªå¤å´ã®ãã©ã³ã¶ã¯ã·ã§ã³ã ããå®éã«$dbhã«ã³ããããçºè¡ãã¾ãã +ã©ã®ã¬ãã«ã®ã©ã®ãã©ã³ã¶ã¯ã·ã§ã³ã§ãããã¼ã«ããã¯ãããã +ãã¹ãããããã©ã³ã¶ã¯ã·ã§ã³å ¨ã¦ã失æãã¾ãã + +=head2 Nested transactions and auto-savepoints + +If savepoints are supported by your RDBMS, it is possible to achieve true +nested transactions with minimal effort. To enable auto-savepoints via nested +transactions, supply the C<< auto_savepoint = 1 >> connection attribute. + +Here is an example of true nested transactions. In the example, we start a big +task which will create several rows. Generation of data for each row is a +fragile operation and might fail. If we fail creating something, depending on +the type of failure, we want to abort the whole task, or only skip the failed +row. + + my $schema = MySchema->connect("dbi:Pg:dbname=my_db"); + + # Start a transaction. Every database change from here on will only be + # committed into the database if the try block succeeds. + use Try::Tiny; + my $exception; + try { + $schema->txn_do(sub { + # SQL: BEGIN WORK; + + my $job = $schema->resultset('Job')->create({ name=> 'big job' }); + # SQL: INSERT INTO job ( name) VALUES ( 'big job' ); + + for (1..10) { + + # Start a nested transaction, which in fact sets a savepoint. + try { + $schema->txn_do(sub { + # SQL: SAVEPOINT savepoint_0; + + my $thing = $schema->resultset('Thing')->create({ job=>$job->id }); + # SQL: INSERT INTO thing ( job) VALUES ( 1 ); + + if (rand > 0.8) { + # This will generate an error, thus setting $@ + + $thing->update({force_fail=>'foo'}); + # SQL: UPDATE thing SET force_fail = 'foo' + # WHERE ( id = 42 ); + } + }); + } catch { + # SQL: ROLLBACK TO SAVEPOINT savepoint_0; + + # There was an error while creating a $thing. Depending on the error + # we want to abort the whole transaction, or only rollback the + # changes related to the creation of this $thing + + # Abort the whole job + if ($_ =~ /horrible_problem/) { + print "something horrible happend, aborting job!"; + die $_; # rethrow error + } + + # Ignore this $thing, report the error, and continue with the + # next $thing + print "Cannot create thing: $_"; + } + # There was no error, so save all changes since the last + # savepoint. + + # SQL: RELEASE SAVEPOINT savepoint_0; + } + }); + } catch { + $exception = $_; + } + + if ($caught) { + # There was an error while handling the $job. Rollback all changes + # since the transaction started, including the already committed + # ('released') savepoints. There will be neither a new $job nor any + # $thing entry in the database. + + # SQL: ROLLBACK; + + print "ERROR: $exception\n"; + } + else { + # There was no error while handling the $job. Commit all changes. + # Only now other connections can see the newly created $job and + # @things. + + # SQL: COMMIT; + + print "Ok\n"; + } + +In this example it might be hard to see where the rollbacks, releases and +commits are happening, but it works just the same as for plain L<<txn_do>>: If +the C<try>-block around C<txn_do> fails, a rollback is issued. If the C<try> +succeeds, the transaction is committed (or the savepoint released). + +While you can get more fine-grained control using C<svp_begin>, C<svp_release> +and C<svp_rollback>, it is strongly recommended to use C<txn_do> with coderefs. + +=head2 Simple Transactions with DBIx::Class::Storage::TxnScopeGuard + +An easy way to use transactions is with +L<DBIx::Class::Storage::TxnScopeGuard>. See L</Automatically creating +related objects> for an example. + +Note that unlike txn_do, TxnScopeGuard will only make sure the connection is +alive when issuing the C<BEGIN> statement. It will not (and really can not) +retry if the server goes away mid-operations, unlike C<txn_do>. + +=head1 SQL + +=head2 Creating Schemas From An Existing Database + +L<DBIx::Class::Schema::Loader> will connect to a database and create a +L<DBIx::Class::Schema> and associated sources by examining the database. + +The recommend way of achieving this is to use the +L<make_schema_at|DBIx::Class::Schema::Loader/make_schema_at> method: + + perl -MDBIx::Class::Schema::Loader=make_schema_at,dump_to_dir:./lib \ + -e 'make_schema_at("My::Schema", { debug => 1 }, [ "dbi:Pg:dbname=foo","postgres" ])' + +This will create a tree of files rooted at C<./lib/My/Schema/> containing +source definitions for all the tables found in the C<foo> database. + +=head2 Creating DDL SQL + +The following functionality requires you to have L<SQL::Translator> +(also known as "SQL Fairy") installed. + +To create a set of database-specific .sql files for the above schema: + + my $schema = My::Schema->connect($dsn); + $schema->create_ddl_dir(['MySQL', 'SQLite', 'PostgreSQL'], + '0.1', + './dbscriptdir/' + ); + +By default this will create schema files in the current directory, for +MySQL, SQLite and PostgreSQL, using the $VERSION from your Schema.pm. + +To create a new database using the schema: + + my $schema = My::Schema->connect($dsn); + $schema->deploy({ add_drop_table => 1}); + +To import created .sql files using the mysql client: + + mysql -h "host" -D "database" -u "user" -p < My_Schema_1.0_MySQL.sql + +To create C<ALTER TABLE> conversion scripts to update a database to a +newer version of your schema at a later point, first set a new +C<$VERSION> in your Schema file, then: + + my $schema = My::Schema->connect($dsn); + $schema->create_ddl_dir(['MySQL', 'SQLite', 'PostgreSQL'], + '0.2', + '/dbscriptdir/', + '0.1' + ); + +This will produce new database-specific .sql files for the new version +of the schema, plus scripts to convert from version 0.1 to 0.2. This +requires that the files for 0.1 as created above are available in the +given directory to diff against. + +=head2 Select from dual + +Dummy tables are needed by some databases to allow calling functions +or expressions that aren't based on table content, for examples of how +this applies to various database types, see: +L<http://troels.arvin.dk/db/rdbms/#other-dummy_table>. + +Note: If you're using Oracles dual table don't B<ever> do anything +other than a select, if you CRUD on your dual table you *will* break +your database. + +Make a table class as you would for any other table + + package MyAppDB::Dual; + use strict; + use warnings; + use base 'DBIx::Class::Core'; + __PACKAGE__->table("Dual"); + __PACKAGE__->add_columns( + "dummy", + { data_type => "VARCHAR2", is_nullable => 0, size => 1 }, + ); + +Once you've loaded your table class select from it using C<select> +and C<as> instead of C<columns> + + my $rs = $schema->resultset('Dual')->search(undef, + { select => [ 'sydate' ], + as => [ 'now' ] + }, + ); + +All you have to do now is be careful how you access your resultset, the below +will not work because there is no column called 'now' in the Dual table class + + while (my $dual = $rs->next) { + print $dual->now."\n"; + } + # Can't locate object method "now" via package "MyAppDB::Dual" at headshot.pl line 23. + +You could of course use 'dummy' in C<as> instead of 'now', or C<add_columns> to +your Dual class for whatever you wanted to select from dual, but that's just +silly, instead use C<get_column> + + while (my $dual = $rs->next) { + print $dual->get_column('now')."\n"; + } + +Or use C<cursor> + + my $cursor = $rs->cursor; + while (my @vals = $cursor->next) { + print $vals[0]."\n"; + } + +In case you're going to use this "trick" together with L<DBIx::Class::Schema/deploy> or +L<DBIx::Class::Schema/create_ddl_dir> a table called "dual" will be created in your +current schema. This would overlap "sys.dual" and you could not fetch "sysdate" or +"sequence.nextval" anymore from dual. To avoid this problem, just tell +L<SQL::Translator> to not create table dual: + + my $sqlt_args = { + add_drop_table => 1, + parser_args => { sources => [ grep $_ ne 'Dual', schema->sources ] }, + }; + $schema->create_ddl_dir( [qw/Oracle/], undef, './sql', undef, $sqlt_args ); + +Or use L<DBIx::Class::ResultClass::HashRefInflator> + + $rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + while ( my $dual = $rs->next ) { + print $dual->{now}."\n"; + } + +Here are some example C<select> conditions to illustrate the different syntax +you could use for doing stuff like +C<oracles.heavily(nested(functions_can('take', 'lots'), OF), 'args')> + + # get a sequence value + select => [ 'A_SEQ.nextval' ], + + # get create table sql + select => [ { 'dbms_metadata.get_ddl' => [ "'TABLE'", "'ARTIST'" ]} ], + + # get a random num between 0 and 100 + select => [ { "trunc" => [ { "dbms_random.value" => [0,100] } ]} ], + + # what year is it? + select => [ { 'extract' => [ \'year from sysdate' ] } ], + + # do some math + select => [ {'round' => [{'cos' => [ \'180 * 3.14159265359/180' ]}]}], + + # which day of the week were you born on? + select => [{'to_char' => [{'to_date' => [ "'25-DEC-1980'", "'dd-mon-yyyy'" ]}, "'day'"]}], + + # select 16 rows from dual + select => [ "'hello'" ], + as => [ 'world' ], + group_by => [ 'cube( 1, 2, 3, 4 )' ], + + + +=head2 Adding Indexes And Functions To Your SQL + +Often you will want indexes on columns on your table to speed up searching. To +do this, create a method called C<sqlt_deploy_hook> in the relevant source +class (refer to the advanced +L<callback system|DBIx::Class::ResultSource/sqlt_deploy_callback> if you wish +to share a hook between multiple sources): + + package My::Schema::Result::Artist; + + __PACKAGE__->table('artist'); + __PACKAGE__->add_columns(id => { ... }, name => { ... }) + + sub sqlt_deploy_hook { + my ($self, $sqlt_table) = @_; + + $sqlt_table->add_index(name => 'idx_name', fields => ['name']); + } + + 1; + +Sometimes you might want to change the index depending on the type of the +database for which SQL is being generated: + + my ($db_type = $sqlt_table->schema->translator->producer_type) + =~ s/^SQL::Translator::Producer:://; + +You can also add hooks to the schema level to stop certain tables being +created: + + package My::Schema; + + ... + + sub sqlt_deploy_hook { + my ($self, $sqlt_schema) = @_; + + $sqlt_schema->drop_table('table_name'); + } + +You could also add views, procedures or triggers to the output using +L<SQL::Translator::Schema/add_view>, +L<SQL::Translator::Schema/add_procedure> or +L<SQL::Translator::Schema/add_trigger>. + + +=head2 ã¹ãã¼ãã®ãã¼ã¸ã§ãã³ã° + +The following example shows simplistically how you might use DBIx::Class to +deploy versioned schemas to your customers. The basic process is as follows: + +ä¸è¨ã®ä¾ã§ã¯ãDBIx::Classã使ã£ã¦ã顧客åãã«ãã¼ã¸ã§ã³ä»ãã®ã¹ãã¼ããã©ããã£ã¦ +ãããã¤ãããããè¦ããã¾ããåºæ¬çãªããã»ã¹ã¯ä¸è¨ã®ããã«ãªãã¾ã: + +=over 4 + +=item 1. + +Create a DBIx::Class schema + +DBIx::Classã¹ãã¼ããä½ãã¾ã + +=item 2. + +Save the schema + +ã¹ãã¼ããä¿åãã¾ã + +=item 3. + +Deploy to customers + +顧客ã«ãããã¤ãã¾ã + +=item 4. + +Modify schema to change functionality + +ã¹ãã¼ããå¤æ´ãã¦ã functionality ãå¤æ´ãã¾ã + +=item 5. + +Deploy update to customers + +顧客ã«æ´æ°ããããã¤ãã¾ã + +=back + +B<Create a DBIx::Class schema> + +B<DBIx::Calssã¹ãã¼ããä½ã> + +This can either be done manually, or generated from an existing database as +described under L</Creating Schemas From An Existing Database> + +ããã¯ãæã§è¡ããã¨ããC<æ¢åã®ãã¼ã¿ãã¼ã¹ããã¹ãã¼ããä½ã>ã§èª¬æãã¾ããã +æ¢åã®ãã¼ã¿ãã¼ã¹ããçæãããã¨ãã§ãã¾ãã + +B<Save the schema> + +B<ã¹ãã¼ããä¿åãã> + +Call L<DBIx::Class::Schema/create_ddl_dir> as above under L</Creating DDL SQL>. + +B<Deploy to customers> + +B<顧客ã«ãããã¤ãã> + +There are several ways you could deploy your schema. These are probably +beyond the scope of this recipe, but might include: + +ã¹ãã¼ãããããã¤ããã®ã«ã¯è¤æ°ã®æ¹æ³ãããã¾ãã +ãã®ã¬ã·ãã®ç¯çãè¶ãããã§ãããå«ãã¦ããã¾ã: + +=over 4 + +=item 1. + +Require customer to apply manually using their RDBMS. + +顧客ã«RDBMSã使ã£ã¦ãæã§é©ç¨ããããã«æ±ãã + +=item 2. + +Package along with your app, making database dump/schema update/tests +all part of your install. + +ã¢ããªã±ã¼ã·ã§ã³ã¨ä¸ç·ã«ããã¼ã¿ãã¼ã¹ã®ãã³ããã¹ãã¼ãã®ã¢ãããã¼ãã +ã¤ã³ã¹ãã¼ã«ã®å ¨ãã¼ãã®ãã¹ããä½ãããã«ãããã±ã¼ã¸ãã + +=back + +B<Modify the schema to change functionality> + +B<æ©è½æ§ãå¤æ´ããããã«ãã¹ãã¼ããå¤æ´ãã> + +As your application evolves, it may be necessary to modify your schema +to change functionality. Once the changes are made to your schema in +DBIx::Class, export the modified schema and the conversion scripts as +in L</Creating DDL SQL>. + +ã¢ããªã±ã¼ã·ã§ã³ãé²åããã«ã¤ããæ©è½æ§ãå¤æ´ããããã«ãã¹ãã¼ããä¿®æ£ããå¿ è¦ãããã§ãããã +DBIx::Classã§ã¹ãã¼ããå¤æ´ãããã以åã®ããã«ä¿®æ£ãããã¹ãã¼ããã¨ã¯ã¹ãã¼ããã +L</Creating DDL SQL>ã«ãããããªå¤æã¹ã¯ãªããã使ãã¾ã + +B<Deploy update to customers> + +B<顧客ã«æ´æ°ããããã¤ãã¾ã> + +Add the L<DBIx::Class::Schema::Versioned> schema component to your +Schema class. This will add a new table to your database called +C<dbix_class_schema_vesion> which will keep track of which version is installed +and warn if the user tries to run a newer schema version than the +database thinks it has. + +Alternatively, you can send the conversion SQL scripts to your +customers as above. + +=head2 çæãããSQLãã¯ã©ã¼ããã + +If the database contains column names with spaces and/or reserved words, they +need to be quoted in the SQL queries. This is done using: + +ãã¼ã¿ãã¼ã¹ã«ã¹ãã¼ã¹ããã³/ã¾ãã¯äºç´èªã®ã¤ããã«ã©ã åãããå ´åã +SQLã¯ã¨ãªå ã§ãã¯ã©ã¼ããããå¿ è¦ãããã¾ãã次ã®ããã«ãã¾ã: + + $schema->storage->sql_maker->quote_char([ qw/[ ]/] ); + $schema->storage->sql_maker->name_sep('.'); + +The first sets the quote characters. Either a pair of matching +brackets, or a C<"> or C<'>: + +1è¡ç®ã¯ãã¯ã©ã¼ãæåãã»ãããã¦ãã¾ãããã©ã±ããã®ãã¢ããC<">, C<'>ã§ãã + + $schema->storage->sql_maker->quote_char('"'); + +Check the documentation of your database for the correct quote +characters to use. C<name_sep> needs to be set to allow the SQL +generator to put the quotes the correct place, and defaults to +C<.> if not supplied. + +æ£ããã¯ã©ã¼ãæåã使ãããã«ããã¼ã¿ãã¼ã¹ã®ããã¥ã¡ã³ãããã§ãã¯ãã¦ãã ããã +C<name_sep>ã¯ãSQLã¸ã§ãã¬ã¼ã¿ã¼ãæ£ããå ´æã«ã¯ã©ã¼ããç½®ãããã«ã +ã»ããããªããã°ããã¾ãããããã©ã«ãã§ã¯C<.>ã«ãªãã¾ãã + +In most cases you should set these as part of the arguments passed to +L<DBIx::Class::Schema/connect>: + + my $schema = My::Schema->connect( + 'dbi:mysql:my_db', + 'db_user', + 'db_password', + { + quote_char => '"', + name_sep => '.' + } + ) + +In some cases, quoting will be required for all users of a schema. To enforce +this, you can also overload the C<connection> method for your schema class: + + sub connection { + my $self = shift; + my $rv = $self->next::method( @_ ); + $rv->storage->sql_maker->quote_char([ qw/[ ]/ ]); + $rv->storage->sql_maker->name_sep('.'); + return $rv; + } + +=head2 Working with PostgreSQL array types + +You can also assign values to PostgreSQL array columns by passing array +references in the C<\%columns> (C<\%vals>) hashref of the +L<DBIx::Class::ResultSet/create> and L<DBIx::Class::Row/update> family of +methods: + + $resultset->create({ + numbers => [1, 2, 3] + }); + + $row->update( + { + numbers => [1, 2, 3] + }, + { + day => '2008-11-24' + } + ); + +In conditions (e.g. C<\%cond> in the L<DBIx::Class::ResultSet/search> family of +methods) you cannot directly use array references (since this is interpreted as +a list of values to be C<OR>ed), but you can use the following syntax to force +passing them as bind values: + + $resultset->search( + { + numbers => \[ '= ?', [numbers => [1, 2, 3]] ] + } + ); + +See L<SQL::Abstract/array_datatypes> and L<SQL::Abstract/Literal SQL with +placeholders and bind values (subqueries)> for more explanation. Note that +L<DBIx::Class> sets L<SQL::Abstract/bindtype> to C<columns>, so you must pass +the bind values (the C<[1, 2, 3]> arrayref in the above example) wrapped in +arrayrefs together with the column name, like this: +C<< [column_name => value] >>. + +=head2 Formatting DateTime objects in queries + +To ensure C<WHERE> conditions containing L<DateTime> arguments are properly +formatted to be understood by your RDBMS, you must use the C<DateTime> +formatter returned by L<DBIx::Class::Storage::DBI/datetime_parser> to format +any L<DateTime> objects you pass to L<search|DBIx::Class::ResultSet/search> +conditions. Any L<Storage|DBIx::Class::Storage> object attached to your +L<Schema|DBIx::Class::Schema> provides a correct C<DateTime> formatter, so +all you have to do is: + + my $dtf = $schema->storage->datetime_parser; + my $rs = $schema->resultset('users')->search( + { + signup_date => { + -between => [ + $dtf->format_datetime($dt_start), + $dtf->format_datetime($dt_end), + ], + } + }, + ); + +Without doing this the query will contain the simple stringification of the +C<DateTime> object, which almost never matches the RDBMS expectations. + +This kludge is necessary only for conditions passed to +L<DBIx::Class::ResultSet/search>, whereas +L<create|DBIx::Class::ResultSet/create>, +L<find|DBIx::Class::ResultSet/find>, +L<DBIx::Class::Row/update> (but not L<DBIx::Class::ResultSet/update>) are all +L<DBIx::Class::InflateColumn>-aware and will do the right thing when supplied +an inflated C<DateTime> object. + +=head2 Using Unicode + +When using unicode character data there are two alternatives - +either your database supports unicode characters (including setting +the utf8 flag on the returned string), or you need to encode/decode +data appropriately each time a string field is inserted into or +retrieved from the database. It is better to avoid +encoding/decoding data and to use your database's own unicode +capabilities if at all possible. + +The L<DBIx::Class::UTF8Columns> component handles storing selected +unicode columns in a database that does not directly support +unicode. If used with a database that does correctly handle unicode +then strange and unexpected data corrupt B<will> occur. + +The Catalyst Wiki Unicode page at +L<http://wiki.catalystframework.org/wiki/tutorialsandhowtos/using_unicode> +has additional information on the use of Unicode with Catalyst and +DBIx::Class. + +The following databases do correctly handle unicode data:- + +=head3 MySQL + +MySQL supports unicode, and will correctly flag utf8 data from the +database if the C<mysql_enable_utf8> is set in the connect options. + + my $schema = My::Schema->connection('dbi:mysql:dbname=test', + $user, $pass, + { mysql_enable_utf8 => 1} ); + + +When set, a data retrieved from a textual column type (char, +varchar, etc) will have the UTF-8 flag turned on if necessary. This +enables character semantics on that string. You will also need to +ensure that your database / table / column is configured to use +UTF8. See Chapter 10 of the mysql manual for details. + +See L<DBD::mysql> for further details. + +=head3 Oracle + +Information about Oracle support for unicode can be found in +L<DBD::Oracle/Unicode>. + +=head3 PostgreSQL + +PostgreSQL supports unicode if the character set is correctly set +at database creation time. Additionally the C<pg_enable_utf8> +should be set to ensure unicode data is correctly marked. + + my $schema = My::Schema->connection('dbi:Pg:dbname=test', + $user, $pass, + { pg_enable_utf8 => 1} ); + +Further information can be found in L<DBD::Pg>. + +=head3 SQLite + +SQLite version 3 and above natively use unicode internally. To +correctly mark unicode strings taken from the database, the +C<sqlite_unicode> flag should be set at connect time (in versions +of L<DBD::SQLite> prior to 1.27 this attribute was named +C<unicode>). + + my $schema = My::Schema->connection('dbi:SQLite:/tmp/test.db', + '', '', + { sqlite_unicode => 1} ); + +=head1 BOOTSTRAPPING/MIGRATING + +=head2 ã¯ã©ã¹ãã¼ã¹ããã¹ãã¼ããã¼ã¹ã»ããã¢ããã¸ã®ç°¡åãªç§»è¡ + +You want to start using the schema-based approach to L<DBIx::Class> +(see L<DBIx::Class::Manual::Intro/Setting it up manually>), but have an +established class-based setup with lots of existing classes that you don't +want to move by hand. Try this nifty script instead: + +L<DBIx::Class>ã¸ã®ã¹ãã¼ããã¼ã¹ã®ã¢ããã¼ãã使ããã(L<SchemaIntro.pod>ãã¿ã¦ãã ãã)ã +ã§ããæ¢åã®å¤§éã®ã¯ã©ã¹ã§ãå¾æ¥ã®ã¯ã©ã¹ãã¼ã¹ã®ã»ããã¢ãããããã +æã§ããããåããããã¯ãªãã¨ãã¾ããæã§åããå¤ããã«ãä¸è¨ã®æ°ã®å©ããã¹ã¯ãªããã +試ãã¦ã¿ã¦ä¸ãã: + + use MyDB; + use SQL::Translator; + + my $schema = MyDB->schema_instance; + + my $translator = SQL::Translator->new( + debug => $debug || 0, + trace => $trace || 0, + no_comments => $no_comments || 0, + show_warnings => $show_warnings || 0, + add_drop_table => $add_drop_table || 0, + validate => $validate || 0, + parser_args => { + 'DBIx::Schema' => $schema, + }, + producer_args => { + 'prefix' => 'My::Schema', + }, + ); + + $translator->parser('SQL::Translator::Parser::DBIx::Class'); + $translator->producer('SQL::Translator::Producer::DBIx::Class::File'); + + my $output = $translator->translate(@args) or die + "Error: " . $translator->error; + + print $output; + +You could use L<Module::Find> to search for all subclasses in the MyDB::* +namespace, which is currently left as an exercise for the reader. + +L<Module::Find>ã使ã£ã¦ãMyDB::*åå空éã«ããå ¨ã¦ã®ãµãã¯ã©ã¹ãæ¢ããã¨ãåºæ¥ã¾ããã +ããã¯ãä»ã®ã¨ãããèªè ã¸ã®èª²é¡ã¨ãã¦ããã¾ãã + +=head1 ã¡ã½ããã®ãªã¼ãã¼ãã¼ã + +L<DBIx::Class> uses the L<Class::C3> package, which provides for redispatch of +method calls, useful for things like default values and triggers. You have to +use calls to C<next::method> to overload methods. More information on using +L<Class::C3> with L<DBIx::Class> can be found in +L<DBIx::Class::Manual::Component>. + +L<DBIx::Class>ã¯L<Class::C3>ããã±ã¼ã¸ã使ã£ã¦ãã¾ããL<Class::C3>ã¯ã¡ã½ããã³ã¼ã«ã +ååå²ãããããã«ä½¿ããã¦ãã¾ããã¡ã½ããããªã¼ãã¼ãã¼ãããããã«ã +C<next::method>ã®å¼ã³åºãã使ããªããã°ããã¾ããã +L<DBIx::Class>ã¨L<Class::C3>ã®å©ç¨ã«é¢ãã詳ããæ å ±ã¯ã +L<DBIx::Class::Manual::Component>ãè¦ã¦ãã ããã + +=head2 åã®ããã©ã«ãã®å¤ãç¨æãã + +It's as simple as overriding the C<new> method. Note the use of +C<next::method>. + +åç´ã«ãC<new>ã¡ã½ããããªã¼ãã¼ã©ã¤ããã¾ãã +C<next::method>ã®ä½¿ãããã«æ³¨æãã¦ãã ããã + + sub new { + my ( $class, $attrs ) = @_; + + $attrs->{foo} = 'bar' unless defined $attrs->{foo}; + + my $new = $class->next::method($attrs); + + return $new; + } + +For more information about C<next::method>, look in the L<Class::C3> +documentation. See also L<DBIx::Class::Manual::Component> for more +ways to write your own base classes to do this. + +C<next::method>ã«ã¤ãã¦ãã詳ããã¯ãL<Class::C3>ã®ããã¥ã¡ã³ããåç §ãã¦ãã ããã +ãããããããã®ãèªåèªèº«ã®ãã¼ã¹ã¯ã©ã¹ãæ¸ãããã®ãããå¤ãã®æ¹æ³ã«ã¤ãã¦ã¯ã +L<DBIx::CLass::Manual::Component>ãè¦ã¦ãã ããã + +People looking for ways to do "triggers" with DBIx::Class are probably +just looking for this. + +DBIx::Classã§"triggers"ãããæ¹æ³ãæ¢ãã¦ãã人ãããããæ¢ãã¦ããã§ãããã + +=head3 ä»ãå¤æ´ãããããã¤ã§ããããã£ã¼ã«ããå¤æ´ãã + +For example, say that you have three columns, C<id>, C<number>, and +C<squared>. You would like to make changes to C<number> and have +C<squared> be automagically set to the value of C<number> squared. +You can accomplish this by wrapping the C<number> accessor with +L<Class::Method::Modifiers>: + +ä¾ãã°ã3ã¤ã®ã«ã©ã ããã£ãã¨ãã¾ããC<id>ãC<number>ãC<squared>ã +C<number>ã«å¤æ´ãå ããC<squared>ã¯èªåçã«ãC<number>ã®äºä¹ã®å¤ã +ã»ãããããã¨ãã¾ããC<number>ã¢ã¯ã»ãµãL<Class::Method::Modifiers>㧠+ã©ãããããã¨ã§ããããã§ãã¾ã: + + around number => sub { + my ($orig, $self) = (shift, shift); + + if (@_) { + my $value = $_[0]; + $self->squared( $value * $value ); + } + + $self->next::method(@_); + } + +Note that the hard work is done by the call to C<next::method>, which +redispatches your call to store_column in the superclass(es). + +C<next::method>ãå¼ã³åºããã¨ã§ã大å¤ãªä»äºãããã¦ãããã¨ã«æ³¨æãã¾ãããã +å¼ã³åºããã(è¤æ°ã®)ã¹ã¼ãã¼ã¯ã©ã¹ã®store_columnã«ååå²ããã¦ã¾ã: + +Generally, if this is a calculation your database can easily do, try +and avoid storing the calculated value, it is safer to calculate when +needed, than rely on the data being in sync. + +=head2 é¢é£ãããªãã¸ã§ã¯ããèªåçã«ä½ã + +You might have a class C<Artist> which has many C<CD>s. Further, you +want to create a C<CD> object every time you insert an C<Artist> object. +You can accomplish this by overriding C<insert> on your objects: + +å¤ãã®C<CD>ãæã£ãC<Artist>ã¯ã©ã¹ãããã¨ãã¾ãã +ããã«ãC<Artist>ãªãã¸ã§ã¯ããã¤ã³ãµã¼ããã度æ¯ã«C<CD>ãªãã¸ã§ã¯ãã +ä½ãããã¨ãã¾ããããã¯ããªãã¸ã§ã¯ãã®C<insert>ããªã¼ããã¼ãããã°ã§ãã¾ã: + + sub insert { + my ( $self, @args ) = @_; + $self->next::method(@args); + $self->create_related ('cds', \%initial_cd_data ); + return $self; + } + +If you want to wrap the two inserts in a transaction (for consistency, +an excellent idea), you can use the awesome +L<DBIx::Class::Storage::TxnScopeGuard>: + + sub insert { + my ( $self, @args ) = @_; + + my $guard = $self->result_source->schema->txn_scope_guard; + + $self->next::method(@args); + $self->create_related ('cds', \%initial_cd_data ); + + $guard->commit; + + return $self + } + +=head2 ã«ã©ã ã®ã¢ã¯ã»ãµãã©ããã³ã°/ãªã¼ãã¼ãã¼ããã + +B<Problem:> + +B<åé¡:> + +Say you have a table "Camera" and want to associate a description +with each camera. For most cameras, you'll be able to generate the description from +the other columns. However, in a few special cases you may want to associate a +custom description with a camera. + + "Camera"ãã¼ãã«ããã£ãã¨ãã¦ãããããã®ã«ã¡ã©ã«ã¤ãã¦ã +説æãé¢é£ä»ãããã¨ãã¾ããã»ã¨ãã©ã®ã«ã¡ã©ã§ã¯ãä»ã®ã«ã©ã ãã説æãçæã§ããã§ãããã +ããããç¹å¥ãªæ°ã±ã¼ã¹ã§ã¯ãã«ã¡ã©ã®ã«ã¹ã¿ã ã®èª¬æãé¢é£ä»ãããã¨ãã¾ãã + +B<Solution:> + +B<解:> + +In your database schema, define a description field in the "Camera" table that +can contain text and null values. + +ãã¼ã¿ãã¼ã¹ã¹ãã¼ãã§ã"Camera"ã«descriptionãã£ã¼ã«ããå®ç¾©ãã +textã¨nullã®å¤ãå«ããã¨ãã§ããããã«ãã¾ãã + +In DBIC, we'll overload the column accessor to provide a sane default if no +custom description is defined. The accessor will either return or generate the +description, depending on whether the field is null or not. + +DBICã¯ãã«ã¹ã¿ã ã® description ãå®ç¾©ããã¦ããªããã°ã +æä¾ããã¦ããã¾ã¨ããªããã©ã«ãã®ã«ã©ã ã¢ã¯ã»ãµããªã¼ãã¼ãã¼ãã§ãã¾ãã +ãã£ã¼ã«ããnullãnullã§ãªããã«ä¾åãã¦ãã¢ã¯ã»ãµã¯descriptionãè¿ããçæãã¾ãã + +First, in your "Camera" schema class, define the description field as follows: + +ã¾ãã"Camera"ã¹ãã¼ãã¯ã©ã¹ã§ãä¸è¨ã®ããã«descriptionãã£ã¼ã«ããå®ç¾©ãã¾ã: + + __PACKAGE__->add_columns(description => { accessor => '_description' }); + +Next, we'll define the accessor-wrapper subroutine: + +次ã«ãã¢ã¯ã»ãµã©ããã¼ãµãã«ã¼ãã³ãå®ç¾©ãã¾ã: + + sub description { + my $self = shift; + + # If there is an update to the column, we'll let the original accessor + # deal with it. + return $self->_description(@_) if @_; + + # Fetch the column value. + my $description = $self->_description; + + # If there's something in the description field, then just return that. + return $description if defined $description && length $descripton; + + # Otherwise, generate a description. + return $self->generate_description; + } + +=head1 ãããã®ã³ã°ã¨ãããã¡ã¤ãªã³ã° + +=head2 Data::Dumperã¨ãDBIx::Classãªãã¸ã§ã¯ã + +L<Data::Dumper> can be a very useful tool for debugging, but sometimes it can +be hard to find the pertinent data in all the data it can generate. +Specifically, if one naively tries to use it like so, + +L<Data::Dumper> ã¯ãããã°ã«ã¨ã¦ã便å©ãªãã¼ã«ã§ããã§ããã +çæãããå ¨ã¦ã®ãã¼ã¿ã®ä¸ã®ã該å½ã®ãã¼ã¿ãè¦ä»ããã®ãé£ããæãããã¾ãã +ç¹ã«ã次ã®ããã«åç´ã«ä½¿ããã¨ãããã + + use Data::Dumper; + + my $cd = $schema->resultset('CD')->find(1); + print Dumper($cd); + +several pages worth of data from the CD object's schema and result source will +be dumped to the screen. Since usually one is only interested in a few column +values of the object, this is not very helpful. + +è¤æ°ãã¼ã¸ã«ããããCDãªãã¸ã§ã¯ãã®ã¹ãã¼ãã¨çµæã®ã½ã¼ã¹ããè¤æ° +ãã¼ã¸ã«ããããã¼ã¿ã¨ãªã£ã¦ã¹ã¯ãªã¼ã³ã«ãã³ãããã¾ããã§ããã +æ®éã¯ãªãã¸ã§ã¯ãã®æ°ã«ã©ã ã®å¤ã®1ã¤ã®ã¿ã«èå³ãããã®ã§ãããã§ã¯ã +ãã¾ã便å©ã§ã¯ããã¾ããã + +Luckily, it is possible to modify the data before L<Data::Dumper> outputs +it. Simply define a hook that L<Data::Dumper> will call on the object before +dumping it. For example, + +幸éã«ããL<Data::Dumper>ãåºåããåã«ãã¼ã¿ãå å·¥ãããã¨ãåºæ¥ã¾ãã +ç°¡åã«ããã¯ãå®ç¾©ããã¨ãL<Data::Dumper>ããã³ãããåã«ããªãã¸ã§ã¯ã㧠+ãããå¼ã³åºãã¾ãã + + package My::DB::CD; + + sub _dumper_hook { + $_[0] = bless { + %{ $_[0] }, + result_source => undef, + }, ref($_[0]); + } + + [...] + + use Data::Dumper; + + local $Data::Dumper::Freezer = '_dumper_hook'; + + my $cd = $schema->resultset('CD')->find(1); + print Dumper($cd); + # dumps $cd without its ResultSource + +If the structure of your schema is such that there is a common base class for +all your table classes, simply put a method similar to C<_dumper_hook> in the +base class and set C<$Data::Dumper::Freezer> to its name and L<Data::Dumper> +will automagically clean up your data before printing it. See +L<Data::Dumper/EXAMPLES> for more information. + +ã¹ãã¼ãã®æ§é ããå ¨ã¦ã®ãã¼ãã«ã¯ã©ã¹ã®ããã®å ±éã®ãã¼ã¹ã¯ã©ã¹ããããã㪠+ãã®ã§ããã°ãåç´ã«ããã¼ã¹ã¯ã©ã¹ã«ãC<_dumper_hook>ã¨åããããªã¡ã½ãããä½ãã +C<$Data::Dumper::Freezer>ã«ãã®ååãã»ãããã¾ãã +L<Data::Dumper>ã¯ãèªåçã«ããã¼ã¿ãåºåããåã«ããããã«ãã¾ãã +L<Data::Dumper/EXAMPLES>ã«ãã詳ããæ å ±ããããã¾ãã + +=head2 ãããã¡ã¤ãªã³ã° + +When you enable L<DBIx::Class::Storage>'s debugging it prints the SQL +executed as well as notifications of query completion and transaction +begin/commit. If you'd like to profile the SQL you can subclass the +L<DBIx::Class::Storage::Statistics> class and write your own profiling +mechanism: + +L<DBIx::Class::Storage>ã®ãããã®ã³ã°ãæå¹ã«ããã°ã +å®è¡ãããSQLã ãã§ãªããã¯ã¨ãªã®å®äºãããã©ã³ã¶ã¯ã·ã§ã³ã®éå§/ã³ããã +ããåºåãã¾ããSQLãåæããããã°ã L<DBIx::Class::Storage::Statistics> +ã¯ã©ã¹ã®ãµãã¯ã©ã¹ãä½ããèªåèªèº«ã®ãããã¡ã¤ãªã³ã°ã¡ã«ããºã ãæ¸ãã¾ã: + + package My::Profiler; + use strict; + + use base 'DBIx::Class::Storage::Statistics'; + + use Time::HiRes qw(time); + + my $start; + + sub query_start { + my $self = shift(); + my $sql = shift(); + my @params = @_; + + $self->print("Executing $sql: ".join(', ', @params)."\n"); + $start = time(); + } + + sub query_end { + my $self = shift(); + my $sql = shift(); + my @params = @_; + + my $elapsed = sprintf("%0.4f", time() - $start); + $self->print("Execution took $elapsed seconds.\n"); + $start = undef; + } + + 1; + +You can then install that class as the debugging object: + +ããããããã®ã¯ã©ã¹ãããããã®ã³ã°ãªãã¸ã§ã¯ãã«ã¤ã³ã¹ãã¼ã«ã§ãã¾ã: + + __PACKAGE__->storage->debugobj(new My::Profiler()); + __PACKAGE__->storage->debug(1); + +A more complicated example might involve storing each execution of SQL in an +array: + +ããè¤éãªä¾ã¨ãã¦ã¯ãé åã«å®è¡ããåSQLã貯ãã¦ãããããªãã®ãå«ãã§ããã: + + sub query_end { + my $self = shift(); + my $sql = shift(); + my @params = @_; + + my $elapsed = time() - $start; + push(@{ $calls{$sql} }, { + params => \@params, + elapsed => $elapsed + }); + } + +You could then create average, high and low execution times for an SQL +statement and dig down to see if certain parameters cause aberrant behavior. +You might want to check out L<DBIx::Class::QueryLog> as well. + +ãããããSQLã¹ãã¼ãã¡ã³ãã®å¹³åãæé·ãæçå®è¡æéãåãã¾ããããã +ãã©ã¡ã¼ã¿ãç°å¸¸ãªæ¯ãèããå¼ãèµ·ããã¦ããã°ãæãä¸ãããã¨ãåºæ¥ãã§ãããã +L<DBIx::Class::QueryLog>ããã§ãã¯ããããããããã¾ããã + +=head1 IMPROVING PERFORMANCE + +=over + +=item * + +Install L<Class::XSAccessor> to speed up L<Class::Accessor::Grouped>. + +=item * + +On Perl 5.8 install L<Class::C3::XS>. + +=item * + +L<prefetch|DBIx::Class::ResultSet/prefetch> relationships, where possible. See +L</Using joins and prefetch>. + +=item * + +Use L<populate|DBIx::Class::ResultSet/populate> in void context to insert data +when you don't need the resulting L<DBIx::Class::Row> objects, if possible, but +see the caveats. + +When inserting many rows, for best results, populate a large number of rows at a +time, but not so large that the table is locked for an unacceptably long time. + +If using L<create|DBIx::Class::ResultSet/create> instead, use a transaction and +commit every C<X> rows; where C<X> gives you the best performance without +locking the table for too long. + +=item * + +When selecting many rows, if you don't need full-blown L<DBIx::Class::Row> +objects, consider using L<DBIx::Class::ResultClass::HashRefInflator>. + +=item * + +See also L</STARTUP SPEED> and L</MEMORY USAGE> in this document. + +=back + +=head1 STARTUP SPEED + +L<DBIx::Class|DBIx::Class> programs can have a significant startup delay +as the ORM loads all the relevant classes. This section examines +techniques for reducing the startup delay. + +These tips are are listed in order of decreasing effectiveness - so the +first tip, if applicable, should have the greatest effect on your +application. + +=head2 Statically Define Your Schema + +If you are using +L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> to build the +classes dynamically based on the database schema then there will be a +significant startup delay. + +For production use a statically defined schema (which can be generated +using L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> to dump +the database schema once - see +L<make_schema_at|DBIx::Class::Schema::Loader/make_schema_at> and +L<dump_directory|DBIx::Class::Schema::Loader/dump_directory> for more +details on creating static schemas from a database). + +=head2 Move Common Startup into a Base Class + +Typically L<DBIx::Class> result classes start off with + + use base qw/DBIx::Class::Core/; + __PACKAGE__->load_components(qw/InflateColumn::DateTime/); + +If this preamble is moved into a common base class:- + + package MyDBICbase; + + use base qw/DBIx::Class::Core/; + __PACKAGE__->load_components(qw/InflateColumn::DateTime/); + 1; + +and each result class then uses this as a base:- + + use base qw/MyDBICbase/; + +then the load_components is only performed once, which can result in a +considerable startup speedup for schemas with many classes. + +=head2 Explicitly List Schema Result Classes + +The schema class will normally contain + + __PACKAGE__->load_classes(); + +to load the result classes. This will use L<Module::Find|Module::Find> +to find and load the appropriate modules. Explicitly defining the +classes you wish to load will remove the overhead of +L<Module::Find|Module::Find> and the related directory operations: + + __PACKAGE__->load_classes(qw/ CD Artist Track /); + +If you are instead using the L<load_namespaces|DBIx::Class::Schema/load_namespaces> +syntax to load the appropriate classes there is not a direct alternative +avoiding L<Module::Find|Module::Find>. + +=head1 MEMORY USAGE + +=head2 Cached statements + +L<DBIx::Class> normally caches all statements with L<< prepare_cached()|DBI/prepare_cached >>. +This is normally a good idea, but if too many statements are cached, the database may use too much +memory and may eventually run out and fail entirely. If you suspect this may be the case, you may want +to examine DBI's L<< CachedKids|DBI/CachedKidsCachedKids_(hash_ref) >> hash: + + # print all currently cached prepared statements + print for keys %{$schema->storage->dbh->{CachedKids}}; + # get a count of currently cached prepared statements + my $count = scalar keys %{$schema->storage->dbh->{CachedKids}}; + +If it's appropriate, you can simply clear these statements, automatically deallocating them in the +database: + + my $kids = $schema->storage->dbh->{CachedKids}; + delete @{$kids}{keys %$kids} if scalar keys %$kids > 100; + +But what you probably want is to expire unused statements and not those that are used frequently. +You can accomplish this with L<Tie::Cache> or L<Tie::Cache::LRU>: + + use Tie::Cache; + use DB::Main; + my $schema = DB::Main->connect($dbi_dsn, $user, $pass, { + on_connect_do => sub { tie %{shift->_dbh->{CachedKids}}, 'Tie::Cache', 100 }, + }); + +=head1 翻訳ã«ã¤ã㦠+ +翻訳è ï¼å è¤æ¦ (ktat.****@gmail*****) + +Perlããã¥ã¡ã³ãæ¥æ¬èªè¨³ Project ã«ã¦ã +Perlã¢ã¸ã¥ã¼ã«ãããã¥ã¡ã³ãã®ç¿»è¨³ãè¡ã£ã¦ããã¾ãã + + http://perldocjp.sourceforge.jp/ + http://sourceforge.jp/projects/perldocjp/ + http://www.freeml.com/perldocjp/ + http://www.perldoc.jp + +=cut Index: docs/modules/DBIx-Class-0.08127/lib/DBIx/Class/Manual/Intro.pod diff -u /dev/null docs/modules/DBIx-Class-0.08127/lib/DBIx/Class/Manual/Intro.pod:1.1 --- /dev/null Fri Apr 29 01:44:57 2011 +++ docs/modules/DBIx-Class-0.08127/lib/DBIx/Class/Manual/Intro.pod Fri Apr 29 01:44:57 2011 @@ -0,0 +1,973 @@ +=encoding utf8 + +=head1 åå + +DBIx::Class::Manual::Intro - DBIx::Class ã¤ã³ãããã¯ã·ã§ã³ + +=head1 ã¤ã³ãããã¯ã·ã§ã³ + +=begin original + +You're bored with SQL, and want a native Perl interface for your database? Or +you've been doing this for a while with L<Class::DBI>, and think there's a +better way? You've come to the right place. + +=end original + +ã§ãSQLã«ãããããã¦ã¾ããï¼ãã¼ã¿ãã¼ã¹ç¨ã«èªç¶ãªPerlã®ã¤ã³ã¿ã¼ãã§ã¼ã¹ã欲ãããªãï¼ +ãããã¯ããã°ããL<Class::DBI>ã§ãããããã¦ãããã©ããã£ã¨è¯ããããããããã¨æããªãã£ãï¼ +è¯ãã¨ããã«æ¥ã¾ãããã + +=head1 THE DBIx::Class WAY + +=begin original + +Here are a few simple tips that will help you get your bearings +with DBIx::Class. + +=end original + +ããã«ã¯DBIx::Classã«æ £ããå©ãã«ãªããããã¤ãã®Tipsãããã¾ãã + +=head2 ãã¼ãã«ã¯Result Class ã«ãªã + +=begin original + +DBIx::Class needs to know what your Table structure looks like. You +do that by defining Result classes. Result classes are defined by +calling methods proxied to L<DBIx::Class::ResultSource>. Each Result +class defines one Table, which defines the Columns it has, along with +any Relationships it has to other tables. (And oh, so much more +besides) The important thing to understand: + +=end original + +DBIx::Class ã¯ã対象ã¨ãªããã¼ãã«ã®æ§é ãã©ããªãã®ãªã®ããç¥ã£ã¦ããå¿ è¦ãããã¾ãã +ãã®ããã«ãResult Classãå®ç¾©ãã¾ããResult Class ã¯L<DBIx::Class::ResultSource> ã +çµç±ãããã¨ã§å®ç¾©ããã¾ããããããã®Result Class ã«ä¸ã¤ã®ãã¼ãã«ãããããã®ã«ã©ã ã +å®ç¾©ãã¾ããä¸ç·ã«ä»ã®ãã¼ãã«ã¨ã®ãã¹ã¦ã®ãªã¬ã¼ã·ã§ã³ãå®ç¾©ãã¾ãã +(ããã¦ãããããã以ä¸ã«ã)ç解ããªãã°ãããªããéè¦ãªãã¨ã¯: + + A Result class == Table + +(most of the time, but just bear with my simplification) + +(ã»ã¨ãã©å¸¸ã«ãã§ããããã®åç´åã«ææ ¢ãã¦ãã ãã) + +=head2 ResultSetã«ã¤ãã¦ã®å ¨ã¦ + +=begin original + +So, we've got some ResultSources defined. Now, we want to actually use those +definitions to help us translate the queries we need into handy perl objects! + +=end original + +ResultSources ãå®ç¾©ããããä»åº¦ã¯ãããã®å®ç¾©ãã +æ軽㪠perl ãªãã¸ã§ã¯ãã«å¿ è¦ãªã¯ã¨ãªãå¤æããããã«ãå®éã«ä½¿ãããã¨æãã¾ã! + +=begin original + +Let's say we defined a ResultSource for an "album" table with three columns: +"albumid", "artist", and "title". Any time we want to query this table, we'll +be creating a L<DBIx::Class::ResultSet> from its ResultSource. For example, the +results of: + +=end original + +"alubum" ãã¼ãã«ã®ResultSource ãå®ç¾©ãã¾ãããã¼ãã«ã«ã¯ï¼ã¤ã®ã«ã©ã ãããã¾ã: +"albumid", "artist", "title" ã§ãã ãã®ãã¼ãã«ã«ã¯ã¨ãªãæããããªãã +ResultSource ããL<DBIx::Class::ResultSet>ãä½ãã¾ããä¾ãã°ãçµæã¯: + + SELECT albumid, artist, title FROM album; + +=begin original + +Would be retrieved by creating a ResultSet object from the album table's +ResultSource, likely by using the "search" method. + +=end original + +album ãã¼ãã« ãã ResultSet ãªãã¸ã§ã¯ããä½ãããã«ããã¼ãã«ã®ResultSource +ããå¼ãã¦ãã¾ãããããã"search" ã¡ã½ããã使ãã¾ãã + +=begin original + +DBIx::Class doesn't limit you to creating only simple ResultSets -- if you +wanted to do something like: + +=end original + +DBIx::Class ã¯åç´ãªResultSet ãä½ãã ãã«ã¯çã¾ãã¾ããã -- ãã次ã®ãããªãã®ã +欲ãããªã: + + SELECT title FROM album GROUP BY title; + +=begin original + +You could easily achieve it. + +=end original + +ç°¡åã«ã§ãã¾ãã + +=begin original + +The important thing to understand: + +=end original + +ç解ãã¹ãéè¦ãªãã¨ã¯ + +=begin original + + Any time you would reach for a SQL query in DBI, you are + creating a DBIx::Class::ResultSet. + +=end original + + DBIã§SQLã¯ã¨ãªãåããã¨ããã¨ãã¯ãã¤ã§ãã + DBIx::Class::ResultSetãä½ã£ã¦ãã¾ãã + +=head2 Search 㯠"prepare"ã®ãããªãã® + +=begin original + +DBIx::Class tends to wait until it absolutely must fetch information from the +database. If you are returning a ResultSet, the query won't execute until you +use a method that wants to access the data. (Such as "next", or "first") + +=end original + +DBIx::Classããã¼ã¿ãã¼ã¹ãã絶対ã«æ å ±ãåå¾ããªããã°ãªããªãæã¾ã§ã +DBIx::Classã¯å¾ ã¤å¾åãããã¾ããResultSetãè¿ãã¦ããã¯ã¨ãªã¯ãã¼ã¿ã« +ã¢ã¯ã»ã¹ããã¡ã½ãã("next"ã"first"ã®ãããª)ã使ãã¾ã§å®è¡ããã¾ããã + +=begin original + +The important thing to understand: + +=end original + +ããã£ã¦ããã¹ãéè¦ãªãã¨ã¯: + +=begin original + + Setting up a ResultSet does not execute the query; retrieving + the data does. + +=end original + + ResultSetã®ã»ããã¢ããã¯ã¯ã¨ãªãå®è¡ãã¾ãã; ãã¼ã¿ã®åå¾ã«ãã£ã¦ + ã¯ã¨ãªãå®è¡ããã¾ãã + +=head2 Search results are returned as Rows + +=begin original + +Rows of the search from the database are blessed into +L<DBIx::Class::Row> objects. + +=end original + +ãã¼ã¿ãã¼ã¹ããã®æ¤ç´¢ã®è¡ã¯ãbless ããã¦L<DBIx::Class::Row>ãªãã¸ã§ã¯ãã«ãªãã¾ãã + +=head1 DBIx::Classã®ã»ããã¢ãã + + +Let's look at how you can set and use your first native L<DBIx::Class> +tree. + +ã¾ãæåã«ãã¤ãã£ãã®L<DBIx::Class>ããªã¼ãã©ã®ããã«ã»ãããã使ãã®ããè¦ã¾ãããã + +=begin original + +First we'll see how you can set up your classes yourself. If you want them to +be auto-discovered, just skip to the next section, which shows you how to use +L<DBIx::Class::Schema::Loader>. + +=end original + +æåã«ãèªåã§ã¯ã©ã¹ãã»ããã¢ããããæ¹æ³ãè¦ã¾ãããã¯ã©ã¹ãèªåã§è¦ä»ãããå ´åã¯ã +ãã®æ¬¡ã®ã»ã¯ã·ã§ã³ã¾ã§ã¹ããããã¦ãã ããããã®æ¬¡ã®ã»ã¯ã·ã§ã³ã§ã¯ãL<DBIx::Class::Schema::Loader> +ã使ã£ãæ¹æ³ã説æãã¾ãã + +=head2 æã§ã»ããã¢ãããã + +=begin original + +First, you should create your base schema class, which inherits from +L<DBIx::Class::Schema>: + +=end original + +ã¾ããåºæ¬ã®ã¹ãã¼ãã¯ã©ã¹ãä½ãã¹ãã§ããL<DBIx::Class::Schema>ããç¶æ¿ãã¾ã: + + package My::Schema; + use base qw/DBIx::Class::Schema/; + +=begin original + +In this class you load your result_source ("table", "model") classes, which we +will define later, using the load_namespaces() method: + +=end original + +ãã®ã¯ã©ã¹ã«ã¯ãresult_source ("table", "model") ã¯ã©ã¹(å¾ã§å®ç¾©ãã¾ã)ããã¼ããã¾ãã +load_namespaces() ã¡ã½ããã使ãã¾ã: + + # load My::Schema::Result::* and their resultset classes + __PACKAGE__->load_namespaces(); + +=begin original + +By default this loads all the Result (Row) classes in the +My::Schema::Result:: namespace, and also any resultset classes in the +My::Schema::ResultSet:: namespace (if missing, the resultsets are +defaulted to be DBIx::Class::ResultSet objects). You can change the +result and resultset namespaces by using options to the +L<DBIx::Class::Schema/load_namespaces> call. + +=end original + +ããã©ã«ãã§ã¯ãMy::Schema::Result:: åå空éã«å ¨ã¦ã®Result(Row)ã¯ã©ã¹ +ãMy::Schema::ResultSet:: åå空éã®ãã¹ã¦ã®çµæã»ããã¯ã©ã¹ããã¼ãããã¾ãã +(if missing, the resultsets are +defaulted to be DBIx::Class::ResultSet objects). You can change the +result and resultset namespaces by using options to the +L<DBIx::Class::Schema/load_namespaces> call. + +=begin original + +It is also possible to do the same things manually by calling +C<load_classes> for the Row classes and defining in those classes any +required resultset classes. + +=end original + +Row ã¯ã©ã¹ã®ããã«C<load_classes>ãå¼ã¶ãã¨ã¨ã +ãããã®ã¯ã©ã¹ã§å ¨ã¦ã®å¿ è¦ãªçµæã»ããã¯ã©ã¹ãå®ç¾©ãããã¨ã§ã +æã§åããã¨ãã§ãã¾ãã + +=begin original + +Next, create each of the classes you want to load as specified above: + +=end original + +次ã«ãä¸ã§æå®ããããã¼ããããã¯ã©ã¹ãããããä½ãã¾ã: + + package My::Schema::Result::Album; + use base qw/DBIx::Class::Core/; + +=begin original + +Load any additional components you may need with the load_components() method, +and provide component configuration if required. For example, if you want +automatic row ordering: + +=end original + +ããããã®ã¯ã©ã¹ã«å¿ è¦ãªè¿½å ã®ã³ã³ãã¼ãã³ãã load_components() ã¡ã½ããã§ãã¼ããã¾ãã +å¿ è¦ãªãã³ã³ãã¼ãã³ãã®è¨å®ãä¸ãã¾ããä¾ãã°ãèªåçãªè¡ã®ä¸¦ã³ãããªã: + + __PACKAGE__->load_components(qw/ Ordered /); + __PACKAGE__->position_column('rank'); + +=begin original + +Ordered will refer to a field called 'position' unless otherwise directed. Here you are defining +the ordering field to be named 'rank'. (NOTE: Insert errors may occur if you use the Ordered +component, but have not defined a position column or have a 'position' field in your row.) + +=end original + +並ã³ããã¯ãä»ã®ãã®ãæ示ãããªããã°ã'position' ã¨å¼ã°ãããã£ã¼ã«ããåç §ãã¾ãã +ããã§ã¯ã'rank' ã¨ããååã®ãã£ã¼ã«ãã並ã³ããã«å®ç¾©ãã¦ãã¾ãã + (注æ: 並ã³ãããããã³ã³ãã¼ãã³ãã使ã£ã¦ããã®ã«ãposition ã«ã©ã ãå®ç¾©ãã¦ããªããã +'position' ãã£ã¼ã«ããåã«ãªããã°ãæ¿å ¥ã¨ã©ã¼ãèµ·ããã§ãããã) + +=begin original + +Set the table for your class: + +=end original + +ã¯ã©ã¹ã«ãã¼ãã«ãã»ãããã¾ã: + + __PACKAGE__->table('album'); + +=begin original + +Add columns to your class: + +=end original + +ã¯ã©ã¹ã«ã«ã©ã ã追å ãã¾ã: + + + __PACKAGE__->add_columns(qw/ albumid artist title rank /); + +=begin original + +Each column can also be set up with its own accessor, data_type and other pieces +of information that it may be useful to have -- just pass C<add_columns> a hash: + +=end original + +ããããã®ã«ã©ã ã¯ãããèªèº«ã®ã¢ã¯ã»ãµãããã£ãã»ãã便å©ãªãdata_type ãä»ã®æ å ±ã +C<add_columns>ã«æ¬¡ã®ãããªããã·ã¥ã渡ãã¾ã: + + __PACKAGE__->add_columns(albumid => + { accessor => 'album', + data_type => 'integer', + size => 16, + is_nullable => 0, + is_auto_increment => 1, + default_value => '', + }, + artist => + { data_type => 'integer', + size => 16, + is_nullable => 0, + is_auto_increment => 0, + default_value => '', + }, + title => + { data_type => 'varchar', + size => 256, + is_nullable => 0, + is_auto_increment => 0, + default_value => '', + }, + rank => + { data_type => 'integer', + size => 16, + is_nullable => 0, + is_auto_increment => 0, + default_value => '', + } + ); + +=begin original + +DBIx::Class doesn't directly use most of this data yet, but various related +modules such as L<DBIx::Class::WebForm> make use of it. Also it allows you to +create your database tables from your Schema, instead of the other way around. +See L<DBIx::Class::Schema/deploy> for details. + +=end original + +ãã®ãã¼ã¿ã®ã»ã¨ãã©ã¯ãã¾ã ãDBIx::Classã§ç´æ¥ã«ä½¿ããã¾ãããã§ããã +L<DBIx::Class::WebForm>ã®ãããªãé¢é£ããæ§ã ãªã¢ã¸ã¥ã¼ã«ãããã使ãã¾ãã +ã¾ããä»ã®ããããã®ä»£ããã«ãã¹ãã¼ããããã¼ã¿ãã¼ã¹ãä½ããã¨ãã§ãã¾ãã +詳ããã¯L<SQL::Translator>ãè¦ã¦ãã ãã: + +=begin original + +See L<DBIx::Class::ResultSource> for more details of the possible column +attributes. + +=end original + +å¯è½ãªã«ã©ã ã®å±æ§ã®è©³ç´°ã«ã¤ãã¦ã¯ã L<DBIx::Class::ResultSource>ãè¦ã¦ãã ããã + +=begin original + +Accessors are created for each column automatically, so My::Schema::Result::Album will +have albumid() (or album(), when using the accessor), artist() and title() +methods. + +=end original + +ã¢ã¯ã»ãµã¯ããããã®ã«ã©ã ç¨ã«ãèªåçã«ä½ããã¾ãã +My::Schema::Result::Albumã¯ãalbumid() (ã¾ãã¯ãã¢ã¯ã»ãµã使ã£ãããalbum())ãartist()ãtitle() +ã®ã¡ã½ããã使ãã¾ãã + +=begin original + +Define a primary key for your class: + +=end original + +ã¯ã©ã¹ã«ãã©ã¤ããªãã¼ãå®ç¾©ãããªã: + + __PACKAGE__->set_primary_key('albumid'); + +If you have a multi-column primary key, just pass a list instead: + +è¤æ°ã«ã©ã ã®ãã©ã¤ããªãã¼ããããªãã代ããã«ããªã¹ãã渡ãã¦ãã ãã: + + __PACKAGE__->set_primary_key( qw/ albumid artistid / ); + +=begin original + +Define this class' relationships with other classes using either C<belongs_to> +to describe a column which contains an ID of another Table, or C<has_many> to +make a predefined accessor for fetching objects that contain this Table's +foreign key: + +=end original + +C<belongs_to>ã使ã£ã¦ãä»ã®ãã¼ãã«ã®IDãå«ãã«ã©ã ã説æãããã¨ã§ã +ã¯ã©ã¹ãã®ãªã¬ã¼ã·ã§ã³ã·ãããå®ç¾©ãããã¨ãåºæ¥ã¾ãã ã¾ããC<has_many>ã§ã +ã«ã©ã ã®1ã¤ã«ããã®ãã¼ãã«ã®å¤é¨ãã¼ãå«ããªãã¸ã§ã¯ããåå¾ãã +å®ç¾©æ¸ã¿ã®ã¢ã¯ã»ãµãä½ãã¾ãã + + # in My::Schema::Result::Artist + __PACKAGE__->has_many('albums', 'My::Schema::Result::Album', 'artist'); + +=begin original + +See L<DBIx::Class::Relationship> for more information about the various types of +available relationships and how you can design your own. + +=end original + +æ§ã ãªã¿ã¤ãã®å¯è½ãªãªã¬ã¼ã·ã§ã³ã·ããã«ã¤ãã¦ã¨ãèªåèªèº«ã®ãªã¬ã¼ã·ã§ã³ã·ãã +ãè¨è¨ããæ¹æ³ã«ã¤ãã¦ã®è©³ããæ å ±ã¯ãL<DBIx::Class::Relationship>ã«ããã¾ãã + +=head2 L<DBIx::Class::Schema::Loader>ã使ã + +=begin original + +This is an external module, and not part of the L<DBIx::Class> distribution. +It inspects your database, and automatically creates classes for all the tables +in your database. + +=end original + +ããã¯å¤é¨ã®ã¢ã¸ã¥ã¼ã«ã§ãããL<DBIx::Class>ã®ãã£ã¹ããªãã¥ã¼ã·ã§ã³ä¸é¨ã§ã¯ããã¾ããã +ãã¼ã¿ãã¼ã¹å ã®å ¨ã¦ã®ãã¼ãã«ç¨ã®ã¯ã©ã¹ãèªåçã«ä½ãã¾ãã + +=begin original + +The simplest way to use it is via the L<dbicdump> script from the +L<DBIx::Class::Schema::Loader> distribution. For example: + +=end original + +æãåç´ãªæ¹æ³ã¯L<dbicdump> ã¹ã¯ãªãããL<DBIx::Class::Schema::Loader> ãã£ã¹ããªãã¥ã¼ã·ã§ã³ +ãã使ããã¨ã§ããä¾: + + $ dbicdump -o dump_directory=./lib MyApp::Schema dbi:mysql:mydb user pass + +=begin original + +If you have a mixed-case database, use the C<preserve_case> option, e.g.: + +=end original + +大æåãå°æåæ··å¨ã®ãã¼ã¿ãã¼ã¹ãªããC<preserve_case>ãªãã·ã§ã³ã使ãã¾ã: + + $ dbicdump -o dump_directory=./lib -o preserve_case=1 MyApp::Schema \ + dbi:mysql:mydb user pass + +=begin original + +If you are using L<Catalyst>, then you can use the helper that comes with +L<Catalyst::Model::DBIC::Schema>: + +=end original + +L<Catalyst>ã使ã£ã¦ãããªããL<Catalyst::Model::DBIC::Schema>ã«ããã +ãã«ãã¼ã使ãã¾ãã + + $ script/myapp_create.pl model MyDB DBIC::Schema MyDB::Schema \ + create=static moniker_map='{ foo => "FOO" }' dbi:SQLite:./myapp.db \ + on_connect_do='PRAGMA foreign_keys=ON' quote_char='"' + +=begin original + +See L<Catalyst::Helper::Model::DBIC::Schema> for more information on this +helper. + +=end original + +ãã®ãã«ãã¼ã«ã¤ãã¦ã®ãã詳ããæ å ±ã¯ãL<Catalyst::Helper::Model::DBIC::Schema>ã +è¦ã¦ãã ããã + +=begin original + +See the L<DBIx::Class::Schema::Loader> and L<DBIx::Class::Schema::Loader::Base> +documentation for more information on the many loader options. + +=end original + +L<DBIx::Class::Schema::Loader>㨠L<DBIx::Class::Schema::Loader::Base> +ã®ããã¥ã¡ã³ããè¦ã¦ãã ãããããããã®ä»ã®ãªãã·ã§ã³ã«é¢ããæ å ±ãããã¾ãã + +=head2 æ¥ç¶ + +=begin original + +To connect to your Schema, you need to provide the connection details or a +database handle. + +=end original + +ã¹ãã¼ãã«æ¥ç¶ããããã«ã¯ãæ¥ç¶ã®ããã®è©³ç´°æ å ±ãããã¼ã¿ã¼ãã¼ã¹ãã³ãã«ãæä¾ããªããã°ããã¾ããã + +=head3 æ¥ç¶ã®ããã®è©³ç´°æ å ±ã§ + +=begin original + +The arguments are the same as for L<DBI/connect>: + +=end original + +å¼æ°ã¯ãL<DBI/connect>ã¨åãã§ã: + + my $schema = My::Schema->connect('dbi:SQLite:/home/me/myapp/my.db'); + +=begin original + +You can create as many different schema instances as you need. So if you have a +second database you want to access: + +=end original + +å¿ è¦ã«å¿ãã¦ãå¤ãã®éã£ãã¹ãã¼ãã¤ã³ã¹ã¿ã³ã¹ãä½ããã¨ãåºæ¥ã¾ãã +2ã¤ç®ã®ãã¼ã¿ãã¼ã¹ããããã¢ã¯ã»ã¹ããããªã: + + my $other_schema = My::Schema->connect( $dsn, $user, $password, $attrs ); + +=begin original + +Note that L<DBIx::Class::Schema> does not cache connections for you. If you use +multiple connections, you need to do this manually. + +=end original + +L<DBIx::Class::Schema>ã¯æ¥ç¶ããã£ãã·ã¥ããªããã¨ã«æ³¨æãã¦ãã ããã +è¤æ°ã®ã³ãã¯ã·ã§ã³ã使ããªããæã§ããªããã°ãªãã¾ããã + +=begin original + +To execute some SQL statements on every connect you can add them as an option in +a special fifth argument to connect: + +=end original + +æ¥ç¶æ¯ã«ãããã¤ãã®sqlæå®è¡ããããªããconnectã®ç¹å¥ãª5çç®ã®å¼æ°ã« +ãªãã·ã§ã³ã¨ãã¦ã¨ãã¦è¿½å ã§ãã¾ã: + + my $another_schema = My::Schema->connect( + $dsn, + $user, + $password, + $attrs, + { on_connect_do => \@on_connect_sql_statments } + ); + +=begin original + +See L<DBIx::Class::Storage::DBI/connect_info> for more information about +this and other special C<connect>-time options. + +=end original + +ãã®ç¹å¥ãªC<connect>-æã®ä»ã®ãªãã·ã§ã³ã«ã¤ãã¦è©³ããã¯ã +L<DBIx::Class::Storage::DBI/connect_info>ãè¦ã¦ãã ããã + +=head3 ãã¼ã¿ãã¼ã¹ãã³ãã«ã§ + +=begin original + +The supplied coderef is expected to return a single connected database handle +(e.g. a L<DBI> C<$dbh>) + +=end original + +ä¸ããããã³ã¼ããªãã¡ã¬ã³ã¹ã¯ä¸ã¤ã®æ¥ç¶ããããã¼ã¿ãã¼ã¹ãã³ãã«ãè¿ããã¨ãæå¾ ããã¾ãã +(e.g. L<DBI> C<$dbh>) + + my $schema = My::Schema->connect ( + sub { Some::DBH::Factory->connect }, + \%extra_attrs, + ); + +=head2 åºæ¬ã®ä½¿ãæ¹ + +=begin original + +Once you've defined the basic classes, either manually or using +L<DBIx::Class::Schema::Loader>, you can start interacting with your database. + +=end original + +åºæ¬ã®ã¯ã©ã¹ãå®ç¾©ããããæã§ãã L<DBIx::Class::Schema::Loader>ã§ãã +ãã¼ã¿ãã¼ã¹ã¸ã®é£æºãå§ãããã¾ãã + +=begin original + +To access your database using your $schema object, you can fetch a +L<DBIx::Class::Manual::Glossary/"ResultSet"> representing each of your tables by +calling the C<resultset> method. + +=end original + +$schemaãªãã¸ã§ã¯ãã§ãã¼ã¿ãã¼ã¹ã«ã¢ã¯ã»ã¹ããã®ã«ã +C<resultset>ã¡ã½ãããå¼ã³åºããã¨ã§ãããããã®ãã¼ãã«ã表ãã +L<DBIx::Class::Manual::Glossary/"ResultSet">ãåãã¾ãã + +=begin original + +The simplest way to get a record is by primary key: + +=end original + +ã¬ã³ã¼ããåããã£ã¨ãç°¡åãªæ¹æ³ã¯ããã©ã¤ããªã¼ãã¼ã§åãæ¹æ³ã§ã: + + my $album = $schema->resultset('Album')->find(14); + +=begin original + +This will run a C<SELECT> with C<albumid = 14> in the C<WHERE> clause, and +return an instance of C<My::Schema::Result::Album> that represents this row. Once you +have that row, you can access and update columns: + +=end original + +C<WHERE>ç¯ã«C<albumid=4>ã§ãC<SELECT>ãå®è¡ããããã®åã表ã +C<My::Schema::Album>ã®ã¤ã³ã¹ã¿ã³ã¹ãè¿ãã¾ãã +ãã®åãããã°ãã«ã©ã ã«ã¢ã¯ã»ã¹ã§ããã¢ãããã¼ãã§ãã¾ãã + + $album->title('Physical Graffiti'); + my $title = $album->title; # $title holds 'Physical Graffiti' + +=begin original + +If you prefer, you can use the C<set_column> and C<get_column> accessors +instead: + +=end original + +ã好ã¿ãªããC<set_column>ã¨C<get_column>ã®ã¢ã¯ã»ãµã代ããã«ä½¿ãã¾ã: + + $album->set_column('title', 'Presence'); + $title = $album->get_column('title'); + +=begin original + +Just like with L<Class::DBI>, you call C<update> to save your changes to the +database (by executing the actual C<UPDATE> statement): + +=end original + +ã¡ããã©L<Class::DBI>ã¨åãããã«ãC<update>ãå¼ãã§ã +å¤æ´ããã¼ã¿ãã¼ã¹ã«ã³ãããã§ãã¾ã: + + $album->update; + +=begin original + +If needed, you can throw away your local changes: + +=end original + +å¿ è¦ãªãã次ã®ããã«ãã¦ããã¼ã«ã«ã®å¤æ´ãæ¨ã¦ããã¨ãã§ãã¾ã: + + $album->discard_changes if $album->is_changed; + +As you can see, C<is_changed> allows you to check if there are local changes to +your object. + +御覧ã®éããC<is_changed>ã§ãªãã¸ã§ã¯ãã«ãã¼ã«ã«ã®å¤æ´ãå ããããã +ã©ããããã§ãã¯ã§ãã¾ãã + +=head2 åã®è¿½å åã³åé¤ + +=begin original + +To create a new record in the database, you can use the C<create> method. It +returns an instance of C<My::Schema::Result::Album> that can be used to access the data +in the new record: + +=end original + +ãã¼ã¿ãã¼ã¹ã«æ°ããã¬ã³ã¼ããä½ãããã«ã¯ãC<create>ã¡ã½ããã使ãã¾ãã +C<My::Schema::Result::Album>ã®ã¤ã³ã¹ã¿ã³ã¹ãè¿ããæ°ããã¬ã³ã¼ãã®ãã¼ã¿ã«ã¢ã¯ã»ã¹ããã®ã« +使ãã¾ã: + + my $new_album = $schema->resultset('Album')->create({ + title => 'Wish You Were Here', + artist => 'Pink Floyd' + }); + +=begin original + +Now you can add data to the new record: + +=end original + +ãããæ°ããã¬ã³ã¼ãã«ãã¼ã¿ã追å ã§ãã¾ã: + + $new_album->label('Capitol'); + $new_album->year('1975'); + $new_album->update; + +=begin original + +Likewise, you can remove it from the database: + +=end original + +åæ§ã«ã次ã®ããã«ãã¦ããã¼ã¿ãã¼ã¹ãããããåé¤ã§ãã¾ã: + + $new_album->delete; + +=begin original + +You can also remove records without retrieving them first, by calling delete +directly on a ResultSet object. + +=end original + +æåã«ã¬ã³ã¼ããåã£ã¦ããã«åé¤ãããã¨ãã§ãã¾ãã +ResultSetãªãã¸ã§ã¯ãã§ç´æ¥ã«deleteãå¼ã³ã¾ãã + + # Delete all of Falco's albums + $schema->resultset('Album')->search({ artist => 'Falco' })->delete; + +=head2 ãªãã¸ã§ã¯ããæ¢ã + +=begin original + +L<DBIx::Class> provides a few different ways to retrieve data from your +database. Here's one example: + +=end original + +L<DBIx::Class>ã¯ããã¼ã¿ãã¼ã¹ãããã¼ã¿ãåå¾ããã®ã«ãããã¤ãã® +éã£ãæ¹æ³ãæä¾ãã¦ãã¾ãã1ã¤ã®ä¾ã¨ãã¦: + + # Find all of Santana's albums + my $rs = $schema->resultset('Album')->search({ artist => 'Santana' }); + +=begin original + +In scalar context, as above, C<search> returns a L<DBIx::Class::ResultSet> +object. It can be used to peek at the first album returned by the database: + +=end original + +ã¹ã«ã©ã³ã³ããã¹ãã§ã¯ãC<search>ã¯ãL<DBIx::Class::ResultSet>ãªãã¸ã§ã¯ã +ãè¿ãã¾ãããã¼ã¿ãã¼ã¹ããè¿ãããæåã®ã¢ã«ãã ãè¦ãã®ã«ä½¿ãã¾ã: + + my $album = $rs->first; + print $album->title; + +=begin original + +You can loop over the albums and update each one: + +=end original + +ã¢ã«ãã ãã«ã¼ããã¦ããããããã¢ãããã¼ãã§ãã¾ã: + + while (my $album = $rs->next) { + print $album->artist . ' - ' . $album->title; + $album->year(2001); + $album->update; + } + +=begin original + +Or, you can update them all at once: + +=end original + +ãããã¯ãä¸åº¦ã«å ¨ã¦ãã¢ãããã¼ãã§ãã¾ã: + + $rs->update({ year => 2001 }); + +=begin original + +In list context, the C<search> method returns all of the matching rows: + +=end original + +ãªã¹ãã³ã³ããã¹ãã§ã¯ãC<search>ã¡ã½ããã¯ãããããåå ¨ã¦ãè¿ãã¾ã: + + # Fetch immediately all of Carlos Santana's albums + my @albums = $schema->resultset('Album')->search( + { artist => 'Carlos Santana' } + ); + foreach my $album (@albums) { + print $album->artist . ' - ' . $album->title; + } + +=begin original + +We also provide a handy shortcut for doing a C<LIKE> search: + +=end original + +C<LIKE>æ¤ç´¢ã®ããã®ãæ軽ãªã·ã§ã¼ãã«ãããããã¾ã: + + # Find albums whose artist starts with 'Jimi' + my $rs = $schema->resultset('Album')->search_like({ artist => 'Jimi%' }); + +=begin original + +Or you can provide your own C<WHERE> clause: + +=end original + +ãããã¯ã次ã®ããã«ãèªåèªèº«ã®C<WHERE>ç¯ã渡ãã¾ã: + + # Find Peter Frampton albums from the year 1986 + my $where = 'artist = ? AND year = ?'; + my @bind = ( 'Peter Frampton', 1986 ); + my $rs = $schema->resultset('Album')->search_literal( $where, @bind ); + +=begin original + +The preferred way to generate complex queries is to provide a L<SQL::Abstract> +construct to C<search>: + +=end original + +è¤éãªã¯ã¨ãªãçæãã好ã¾ããæ¹æ³ã¯ãL<SQL::Abstract>ã®æ§é ã +C<search>ã«æ¸¡ããã¨ã§ã: + + my $rs = $schema->resultset('Album')->search({ + artist => { '!=', 'Janis Joplin' }, + year => { '<' => 1980 }, + albumid => { '-in' => [ 1, 14, 15, 65, 43 ] } + }); + +=begin original + +This results in something like the following C<WHERE> clause: + +=end original + +çµæã¯ãä¸è¨ã®C<WHERE>ç¯ã¨åæ§ã§ã: + + WHERE artist != 'Janis Joplin' + AND year < 1980 + AND albumid IN (1, 14, 15, 65, 43) + +=begin original + +For more examples of complex queries, see L<DBIx::Class::Manual::Cookbook>. + +=end original + +è¤éãªã¯ã¨ãªã®ä»ã®ä¾ã¯L<DBIx::Class::Manual::Cookbook>ã«ããã¾ãã + +=begin original + +The search can also be modified by passing another hash with +attributes: + +=end original + +å±æ§ã«ä»ã®ããã·ã¥ã渡ããã¨ã§ãsearch ãä¿®æ£ã§ãã¾ã: + + my @albums = My::Schema->resultset('Album')->search( + { artist => 'Bob Marley' }, + { rows => 2, order_by => 'year DESC' } + ); + +=begin original + +C<@albums> then holds the two most recent Bob Marley albums. + +=end original + +C<@albumns> ã«ã¯ãææ°ã®Bob Marleyã®ã¢ã«ãã 2ã¤ãããã¾ãã + +=begin original + +For more information on what you can do with a L<DBIx::Class::ResultSet>, see +L<DBIx::Class::ResultSet/METHODS>. + +=end original + +L<DBIx::Class::ResultSet>ã§ä½ãåºæ¥ããã«ã¤ãã¦ã®ãã詳ããæ å ±ã¯ã +L<DBIx::Class::ResultSet/METHODS>ãè¦ã¦ãã ããã + +For a complete overview of the available attributes, see +L<DBIx::Class::ResultSet/ATTRIBUTES>. + +使ããå±æ§ã®å®å ¨ãªæ¦è¦³ã¯ãL<DBIx::Class::ResultSet/ATTRIBUTES>ãè¦ã¦ãã ãã + +=head1 注æ + +=head2 The Significance and Importance of Primary Keys + +The concept of a L<primary key|DBIx::Class::ResultSource/set_primary_key> in +DBIx::Class warrants special discussion. The formal definition (which somewhat +resembles that of a classic RDBMS) is I<a unique constraint that is least +likely to change after initial row creation>. However this is where the +similarity ends. Any time you call a CRUD operation on a row (e.g. +L<delete|DBIx::Class::Row/delete>, +L<update|DBIx::Class::Row/update>, +L<discard_changes|DBIx::Class::Row/discard_changes>, +etc.) DBIx::Class will use the values of of the +L<primary key|DBIx::Class::ResultSource/set_primary_key> columns to populate +the C<WHERE> clause necessary to accomplish the operation. This is why it is +important to declare a L<primary key|DBIx::Class::ResultSource/set_primary_key> +on all your result sources B<even if the underlying RDBMS does not have one>. +In a pinch one can always declare each row identifiable by all its columns: + + __PACKAGE__->set_primary_keys (__PACKAGE__->columns); + +Note that DBIx::Class is smart enough to store a copy of the PK values before +any row-object changes take place, so even if you change the values of PK +columns the C<WHERE> clause will remain correct. + +If you elect not to declare a C<primary key>, DBIx::Class will behave correctly +by throwing exceptions on any row operation that relies on unique identifiable +rows. If you inherited datasets with multiple identical rows in them, you can +still operate with such sets provided you only utilize +L<DBIx::Class::ResultSet> CRUD methods: +L<search|DBIx::Class::ResultSet/search>, +L<update|DBIx::Class::ResultSet/update>, +L<delete|DBIx::Class::ResultSet/delete> + +For example, the following would not work (assuming C<People> does not have +a declared PK): + + my $row = $schema->resultset('People') + ->search({ last_name => 'Dantes' }) + ->next; + $row->update({ children => 2 }); # <-- exception thrown because $row isn't + # necessarily unique + +So instead the following should be done: + + $schema->resultset('People') + ->search({ last_name => 'Dantes' }) + ->update({ children => 2 }); # <-- update's ALL Dantes to have children of 2 + +=head2 Problems on RHEL5/CentOS5 + +There used to be an issue with the system perl on Red Hat Enterprise +Linux 5, some versions of Fedora and derived systems. Further +information on this can be found in L<DBIx::Class::Manual::Troubleshooting> + +=head1 SEE ALSO + +=over 4 + +=item * L<DBIx::Class::Manual::Cookbook> + +=back + +=head1 翻訳ã«ã¤ã㦠+ +翻訳è ï¼å è¤æ¦ (ktat.****@gmail*****) + +Perlããã¥ã¡ã³ãæ¥æ¬èªè¨³ Project ã«ã¦ã +Perlã¢ã¸ã¥ã¼ã«ãããã¥ã¡ã³ãã®ç¿»è¨³ãè¡ã£ã¦ããã¾ãã + + http://perldocjp.sourceforge.jp/ + http://sourceforge.jp/projects/perldocjp/ + http://www.freeml.com/perldocjp/ + http://www.perldoc.jp + +=cut