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