);
... and you'll get back a perfect L<DBIx::Class::ResultSet> (except, of course,
-that you cannot modify the rows it contains, ie. cannot call L</update>,
+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.
# SELECT name name, LENGTH( name )
# FROM artist
-Note that the C<as> attribute B<has absolutely nothing to do> with the sql
+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:
are in any way unsure about the use of the attributes above (C< join
>, C< select >, C< as > and C< group_by >).
-=head2 Subqueries (EXPERIMENTAL)
+=head2 Subqueries
You can write subqueries relatively easily in DBIC.
artist_id => { 'IN' => $inside_rs->get_column('id')->as_query },
});
-The usual operators ( =, !=, IN, NOT IN, etc) are supported.
+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:
WHERE artist_id = me.artist_id
)
-=head3 EXPERIMENTAL
-
-Please note that subqueries are considered an experimental feature.
-
=head2 Predefined searches
You can write your own L<DBIx::Class::ResultSet> class by inheriting from it
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
+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.
package My::App::Schema;
- use base DBIx::Class::Schema;
+ use base 'DBIx::Class::Schema';
# load subclassed classes from My::App::Schema::Result/ResultSet
__PACKAGE__->load_namespaces;
use strict;
use warnings;
- use base My::Shared::Model::Result::Baz;
+ 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
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
-seperate proxy-class files for this. We would be copying all the user
+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.
=head1 TRANSACTIONS
+=head2 Transactions with 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:
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.
-
+
=head2 Nested transactions and auto-savepoints
If savepoints are supported by your RDBMS, it is possible to achieve true
my $schema = MySchema->connect("dbi:Pg:dbname=my_db");
# Start a transaction. Every database change from here on will only be
- # commited into the database if the eval block succeeds.
+ # committed into the database if the eval block succeeds.
eval {
$schema->txn_do(sub {
# SQL: BEGIN WORK;
};
if ($@) {
# There was an error while handling the $job. Rollback all changes
- # since the transaction started, including the already commited
+ # since the transaction started, including the already committed
# ('released') savepoints. There will be neither a new $job nor any
# $thing entry in the database.
the C<eval>-block around C<txn_do> fails, a rollback is issued. If the C<eval>
succeeds, the transaction is committed (or the savepoint released).
-While you can get more fine-grained controll using C<svp_begin>, C<svp_release>
+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. I 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
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 trys to run a newer schema version than the
+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
+Alternatively, you can send the conversion SQL scripts to your
customers as above.
=head2 Setting quoting for the generated SQL
}
);
-In conditions (eg. C<\%cond> in the L<DBIx::Class::ResultSet/search> family of
+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:
sub insert {
my ( $self, @args ) = @_;
$self->next::method(@args);
- $self->cds->new({})->fill_from_artist($self)->insert;
+ $self->create_related ('cds', \%initial_cd_data );
return $self;
}
-where C<fill_from_artist> is a method you specify in C<CD> which sets
-values in C<CD> based on the data in the C<Artist> object you pass in.
+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 Wrapping/overloading a column accessor