=head2 Manual Result class creation (and understanding Loader results)
-This section covers the common and oft used CREATE DDL statements that DBIx::Class can replaces with Perl classes: B<CREATE TABLE>, B<CREATE VIEW> and B<CREATE INDEX>. The classes can be used to write the actual SQL DDL to the database or disc, if required.
+This section covers the common and oft used CREATE DDL statements that DBIx::Class can replace with Perl classes: B<CREATE TABLE>, B<CREATE VIEW> and B<CREATE INDEX>. The classes can be used to write the actual SQL DDL to the database or disc, if required.
=head3 CREATE TABLE
-=head4 Standard basic table creation in SQL:
+=head4 Standard basic table creation in SQL
CREATE TABLE users (
id INTEGER AUTO_INCREMENT,
The fully descriptive version is required if you want to have DBIx::Class create your CREATE TABLE sql for you later. Many DBIC components also use settings in the column info hashrefs to decide how to treat the data for those columns.
-=head4 Table creation with references:
+=head4 Table creation with references
A relational database isn't worth much if we don't actually use references and constraints, so here is an example which constrains the B<user_id> column to only contain B<id> values from the *users* table.
# Defaults to 'DBIx::Class::ResultSource::Table' unless specified like this
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
- __PACKAGE__->table('user_posts');
+ __PACKAGE__->table('userposts');
# Do not emit SQL DDL for this particular resultsource
__PACKAGE__->result_source_instance->is_virtual(1);
},
);
- __PACKAGE__->set_primary_key('user_id, post_id');
+ __PACKAGE__->set_primary_key('user_id', 'post_id');
=head3 CREATE INDEX
CREATE INDEX user_email_idx ON user (username, email);
-These are not created or used by DBIx::Class itself, but can be added so that deploying (creating DDL SQL from your Schema) can include them.
+These are not created or used by DBIx::Class itself, but can be added so that deploying (creating DDL SQL from your schema) can include them.
-The B<sqlt_deply_hook> method allows you to add L<SQL::Translator> code to your Result class. It is called with the SQL::Translator::Schema::Table object, and allows you to amend the Table before it is converted into SQL.
+The B<sqlt_deploy_hook> method allows you to add L<SQL::Translator> code to your Result class. It is called with the SQL::Translator::Schema::Table object, and allows you to amend the Table before it is converted into SQL.
sub sqlt_deploy_hook {
my ($self, $sqlt_table) = @_;
=back
This can also be done as one statement, skipping the extra temporary
-variable, if it is not needed later:
+variable if it is not needed later:
$schema->resultset('User')->find({ id => 1 })->delete;
In the first variant, the $fred_user row object will still contain the
last known contents of Fred's data. A call to $fred_user->L<in_storage|DBIx::Class::Row/in_storage> will return
-false (0), showing that the row object is no longer connected to a actual
+false (0), showing that the row object is no longer connected to an actual
database row.
=head2 Delete one or more rows based on a WHERE clause
=back
Unlike the single row deletion above, the contents of the rows to be
-deleted are never fetched from the database, so no record of them now
-remains.
+deleted are never fetched from the database, so no record of them
+remains afterwards.
NOTE: Calling B<delete> on a ResultSet object will not run any
-overridden B<delete> methods in your Result Classes or any loaded
+overridden B<delete> methods in your Result classes or any loaded
Components. To force these to run, call B<delete_all> instead:
$old_posts->delete_all();
WHERE user_id = 1;
-Cascading deletes ensure the integrity of your data, if a User row is
+Cascading deletes ensure the integrity of your data. If a User row is
removed, then any items belonging to that user (for example comments
-created by the user), should also be removed.
+created by the user) should also be removed.
-NOTE: This is a rather drastic action, to prevent problems in your
+NOTE: This is a rather drastic action. To prevent problems in your
application, consider de-activating accounts instead of removing them!
For the time being DBIx::Class defaults to cascade deletion for the
references>.
If your database is already properly set up to cascade deletes for you,
-you can noop DBIx::Class' extra cascading statements:
+you can turn off DBIx::Class' extra cascading statements:
__PACKAGE__->has_many('posts',
'MyDatabase::Schema::Result::Post',
'user_id',
{ cascade_delete => 0 });
-
-
=back
-Note that in void context you can skip passing primary key values that will be supplied by the database, and any other values that are allowed to DEFAULT. However no code in your Result classes will be run (eg InflateColumn components).
+Note that in void context you can skip passing primary key values that will be supplied by the database, and any other values that are allowed to DEFAULT. However no code in your Result classes will be run (e.g. InflateColumn components).
=head2 Constructing and inserting Row object
my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
-(ideally you will always have one of these handy, no need to make many connections to the database)
+(Ideally you will always have one of these handy, no need to make many connections to the database.)
NB: DBIx::Class does not store a Singleton schema object for you, calling C<connect> again will create a new Schema object with a new database connection. Avoid doing this, store and re-use the Schema object.
password => 'secretpass',
});
- $newuser is now a DBIx::Class::Row object, containing uninserted data. This can be verified by calling $newuser->in_storage, which will return false.
+B<$newuser> is now a DBIx::Class::Row object, containing uninserted data. This can be verified by calling C<< $newuser->in_storage >>, which will return false.
-=item 3. Insert the users data into the database:
+=item 3. Insert the user's data into the database:
$newuser->insert();
- $newuser has been updated to contain the auto-incremented id value in its primary key field (id). $newuser->in_storage now returns true.
+$newuser has been updated to contain the auto-incremented id value in its primary key field (id). C<< $newuser->in_storage >> now returns true.
You can also shortcut these two methods if you don't need to build up the Row object before inserting:
=head2 Fetching column values from a Row object
-The Row object represents the results from a single data source in the query. The column values can be retrieved by using the accessor methods named after the column names. (By default that is, accessors can be changed in the L<Result Class|DBIx::Class::ResulSource> if needed).
+The Row object represents the results from a single data source in the query. The column values can be retrieved by using the accessor methods named after the column names. (By default that is; accessors can be changed in the L<Result Class|DBIx::Class::ResulSource> if needed.)
print $user->username;
FROM users
WHERE dob = '1910-02-01';
-To select all users born on the date '1910-02-01', we can use the B<search> method to prepare a query. Search returns a new resultset with the search conditions stored in it, it does not run the query on the database.
+To select all users born on the date '1910-02-01', we can use the B<search> method to prepare a query. Search returns a new resultset with the search conditions stored in it; it does not run the query on the database.
=over
=head2 SELECT with different WHERE conditions
-Below are shown some common SQL where conditions. The syntax for these is parsed by a module called L<SQL::Abstract> which DBIx::Class uses. They can all be passed to the B<search> method as conditions.
+Shown below are some common SQL WHERE conditions. The syntax for these is parsed by a module called L<SQL::Abstract>, which DBIx::Class uses. They can all be passed to the B<search> method as conditions.
SELECT id, username, dob, realname, password
FROM users
WHERE username LIKE 'fred%';
- my $name_search = $schema->resultset('User')->search(
- { username => { '-like' => 'fred%' } }
- );
+=cut
+
+=pod
+
+ my $name_search = $schema->resultset('User')->search(
+ { username => { '-like' => 'fred%' } }
+ );
+
+=cut
+
+=pod
SELECT id, username, dob, realname, password
FROM users
WHERE dob BETWEEN '1910-01-01' AND '1910-12-31';
- my $year_dob_search = $schema->resultset('User')->search(
- { dob => { '-between' => ['1910-01-01', '1910-12-31'] } }
- );
+=cut
+
+=pod
+
+ my $year_dob_search = $schema->resultset('User')->search(
+ { dob => { '-between' => ['1910-01-01', '1910-12-31'] } }
+ );
+
+=cut
+
+=pod
SELECT id, username, dob, realname, password
FROM users
WHERE dob IN ('1910-02-01', '1910-02-02');
- my $feb_dob_search = $schema->resultset('User')->search(
- { dob => { '-in' => ['1910-02-01', '1910-02-02'] } }
- );
+=cut
+
+=pod
+
+ my $feb_dob_search = $schema->resultset('User')->search(
+ { dob => { '-in' => ['1910-02-01', '1910-02-02'] } }
+ );
+
+=cut
+
+=pod
SELECT id, username, dob, realname, password
FROM users
WHERE dob >= 1911-01-01;
- my $next_year_dob = $schema->resultset('User')->search(
- { dob => { '>=', '1911-01-01' } }
- );
+=cut
+
+=pod
+
+ my $next_year_dob = $schema->resultset('User')->search(
+ { dob => { '>=', '1911-01-01' } }
+ );
=head2 SELECT with WHERE condition on JOINed table
=back
-Note that the string "user", used twice here, refers to the B<name> of the L<Relationship|DBIx::Class::Manual::SQLHackers::CREATE> between the "Post" source and the "User" source. All dealings with related tables are refered to by relationship names, not table names.
+Note that the string "user", used twice here, refers to the B<name> of the L<Relationship|DBIx::Class::Relationship> between the "Post" source and the "User" source. All dealings with related tables are referred to by relationship names, not table names.
To run the query, use the B<all> or B<next> methods show at the beginning of this page.
=back
-Note that accessors for other columns not fetched will return B<undef>, which is also the perl equivalent of the SQL C<NULL> value. To disambiguate between an C<undef> meaning "this column is set null" and "we never retrieved the value of this column" use L<DBIx::Class::Row/has_column_loaded>.
+Note that accessors for other columns not fetched will return B<undef>, which is also the perl equivalent of the SQL C<NULL> value. To disambiguate between an C<undef> meaning "this column is set null" and "we never retrieved the value of this column" use L<DBIx::Class::Row::has_column_loaded|DBIx::Class::Row/has_column_loaded>.
=head2 SELECT with aggregates
SELECT COUNT(*)
FROM users;
-To find out how many users exist. This simple one can be achieved with a built-in method, B<count>.
+Finding out how many users exist can be achieved with a built-in method, B<count>.
=over
my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
-=item 2. Call the *count* method on the resultset for the [Source] you wish to fetch data from:
+=item 2. Call the B<count> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from:
my $posts_count = $schema->resultset('Post')->count();
=item 2. Call the B<get_column> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from, then the B<sum> method:
- my $sum_prices = $schema->resultset('Price')->get_column('amount')
- ->sum();
+ my $sum_prices = $schema->resultset('Price')->get_column('amount')->sum();
=back
The result is just a number.
-The alternate way uses the B<search> method and is easier to build further refinements into.
+The alternative way uses the B<search> method and is easier to build further refinements into.
=over
my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
-=item 2. Call the *search* method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to group data on:
+=item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to group data on:
my $posts_count_per_user = $schema->resultset('User')->search(
{ },
FROM users
FOR UPDATE
-To fetch data and lock it for updating from other transactions, use the B<for> attribute and pass it the value B<update>. This should be done inside a L<Transaction|DBIx::Class::Manual::SQLHackers::Transaction>.
+To fetch data and lock it for updating from other transactions, use the B<for> attribute and pass it the value B<update>. This should be done inside a L<Transaction|DBIx::Class::Manual::SQLHackers::Transactions>.
=over
=back
-The resultset and rows will be returned as normal, and can be used to update the rows without worrying about other
+The resultset and rows will be returned as normal, and can be used to update the rows without worrying about other processes modifying the table behind your back.
=head2 SELECT with LIMIT and OFFSET
This will return exactly 10 row objects, sorted by descending date of birth of the users, starting at the 11th row of the sorted result.
=back
-
UPDATE users SET username = 'fred' WHERE id = 1;
COMMIT;
-To create a transaction, put all your changes inside a coderef, and pass it to the B<txn_do> method on the Schema object. Transactions can also be safely nested,
-in which case all but the top level transaction blocks become noops.
+To create a transaction, put all your changes inside a coderef and pass it to the B<txn_do> method on the Schema object. Transactions can also be safely nested,
+in which case all but the top level transaction blocks become no-ops.
=over
Individual rows may be updated via their Result object in one of two
ways. You can create an object representing an existing database table
-row and hold it in your programmes memory, passing it around from
+row and hold it in your program's memory, passing it around from
function to function changing its values, before actually updating
the contents into the database. This is a delayed update.
in the table.
NOTE: Running a direct update on a row object that already has changed
-values, will *also* apply those values to the database. If values are
-changed both on the object, and in the update method arguments, the
+values will B<also> apply those values to the database. If some values are
+changed both on the object and in the update method arguments, the
argument values take precedence.
=head2 Updating a row in memory
-To create a Row object for delayed update (or other manipulations), first fetch it from the database as described in L<Simple SELECT|DBIx::Class::Manual::SQLHackers::SELECT/Simple SELECT>.
+To create a Row object for delayed update (or other manipulations), first fetch it from the database as described in L<Simple SELECT|DBIx::Class::Manual::SQLHackers::SELECT/Simple SELECT, one row via the primary key>.
=over
This value has not yet changed in the database, we can make the actual
-update by calling *update*:
+update by calling B<update>:
-=item 4. Update the set value(s) into the database:
+=item 4. Write the new value(s) into the database:
$fred_user->update();
database if one or more of the columns have changed. The internal
tracking of which columns have been changed can be queried using
several methods. B<is_changed> returns true (or a list of changed
-column names), if any column values have changed. B<is_column_changed>
+column names) if any column values have changed. B<is_column_changed>
will return true or false for the given column name argument. The
previous values of the columns are not stored.
my $fred_user = $schema->resultset('User')->find({ id => 1 });
- The Row object has an B<update> method that will change the values on
-the object, and send an UPDATE query to the database.
+The Row object has an B<update> method that will change the values on
+the object and send an UPDATE query to the database.
=item 3. Call the B<update> method, passing it a hashref of new data:
=back
-See also: L</Direct update versus delayed update>.
-
-## Removed from UPDATE.pod:
+See also: L</Single row direct update versus delayed update>.
=head2 Update a row or rows using a column calculation
$fred_user->update({ username => \['username || ?', [ {} => '.uk'] ] });
-The \[ .. ] syntax here is base on L<SQL::Abstract/Literal SQL with placeholders and bind values (subqueries)>, and adds some extra syntax for the "values" to be able to supply things like the exact SQL bind type and so on. This extra syntax will be documented in DBIx::Class soon.
+The C<\[ ... ]> syntax here is based on L<SQL::Abstract/Literal SQL with placeholders and bind values (subqueries)>, and adds some extra syntax for the "values" to be able to supply things like the exact SQL bind type and so on. This extra syntax will be documented in DBIx::Class soon.
=back
=item 3. Call the B<update_or_create> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to update data in:
- $schema->resultset('User')->update_or_create(
- {
- username => 'joebloggs',
- dob => '2010-09-10',
- realname = 'Joe Bloggs'
- },
- {
- key => 'uniq_username'
- }
- );
+ $schema->resultset('User')->update_or_create(
+ {
+ username => 'joebloggs',
+ dob => '2010-09-10',
+ realname = 'Joe Bloggs'
+ },
+ {
+ key => 'uniq_username'
+ }
+ );
-=item 4. Close off the transaction / coderef:
+=item 4. Close off the coderef / transaction:
} );
A transaction is issued containing two statements, a B<SELECT> and then
either an B<INSERT> or an B<UPDATE> depending on the results.
-Do not use this method if you definitely don't have either the primary
-key, or a unique index value available. The B<find> method used under
+Do not use this method if you don't definitely have either the primary
+key or a unique index value available. The B<find> method used under
the hood will probably not do what you expect. In this case, manually
-run a separate B<search> method call to check for existance, and then
+run a separate B<search> method call to check for existence, and then
call B<create>.