++ed by:
AWNCORP PERLANCAR KEEDI

3 PAUSE users
7 non-PAUSE users.

Laurent Dami
and 1 contributors

NAME

DBIx::DataModel::Doc::Reference - All methods of DBIx::DataModel

DOCUMENTATION CONTEXT

This chapter is part of the DBIx::DataModel manual.

DESCRIPTION

This chapter is the detailed description of DBIx::DataModels methods for creating and using schemas.

Automatic schema generation from external sources is not covered here; see DBIx::DataModel::Schema::Generator.

Detailed use of statements is not covered here either, because explicit programming of the various statement phases (sqlize, prepare, bind, execute, etc.) is seldom needed. If you want to finely tune these operations, read the DESIGN section of the manual (purpose, lifecycle, etc.), and the DBIx::DataModel::Statement page.

GENERAL CONVENTION

Method names starting with an uppercase letter are meant to be compile-time class methods. These methods will typically be called when loading a module like 'MySchema.pm', and therefore will be executed during the BEGIN phase of the Perl compiler. They instruct the compiler to create classes, methods and datastructures for representing the elements of a database schema. For those methods, the return value is the classname again, so that they can be chained :

   MySchema->Table(...)
           ->Table(...)
           ->Association(...);

Method names starting with a lowercase letter are meant to be usual run-time methods, either for classes or for instances; usually these methods do not return the classname and therefore cannot be chained.

SCHEMA CREATION

Schema

  DBIx::DataModel->Schema($schemaName, %options)

Creates a new Perl class of name $schemaName that represents a database schema. That class inherits from DBIx::DataModel::Schema. Possible options are :

dbh => $dbh

Connects the schema to a DBI database handle. This can also be set or reset later via the "dbh" method.

sqlAbstract => $sql_abstract_instance

Specifies an instance of SQL::Abstract to be used by this schema. If none is given, a default instance will be created automatically, with no specific option.

sqlDialect => $dialect

SQL has no standard syntax for performing joins, so if your database wants a particular syntax you will need to declare it. Current builtin dialects are either 'MsAccess', 'BasisODBC', 'BasisJDBC' or 'Default' (contributions to enrich this list are welcome). Otherwise $dialect can also be a hashref in which you supply the following information :

innerJoin

a string in sprintf format, with placeholders for the left table, the right table and the join criteria. Default is %s INNER JOIN %s ON %s. If your database does not support inner joins, set this to undef and the generated SQL will be in the form T1, T2, ... Tn WHERE ... AND ... .

leftJoin

a string for left outer joins. Default is %s LEFT OUTER JOIN %s ON %s.

joinAssociativity

either left or right

columnAlias

a string for generating column aliases. Default is %s AS %s.

tableParent => 'My::Parent::Class::For::Tables'

Specifies a parent class from which table classes will inherit. The default is DBIx::DataModel::Table. The argument may also be an arrayref of several parent class names.

viewParent => 'My::Parent::Class::For::Views'

Specifies a parent class from which table classes will inherit. The default is DBIx::DataModel::View. The argument may also be an arrayref of several parent class names.

statementClass => 'My::Statement::Class'

Specifies a class to be used for statements returned by the select() method, instead of the default DBIx::DataModel::Statement. The specified class should of course implement the same API. It may be useful to override it for performing driver-specific operations on the underlying dbh (see for example DBIx::DataModel::Statement::JDBC, with added methods for scrolling the result set).

placeholderPrefix => $string

Specifies a prefix to distinguish named placeholders from ordinary values in parameters to statements. The default is the question mark ?.

SCHEMA POPULATION (CREATING TABLES, VIEWS AND ASSOCIATIONS)

Table

  MySchema->Table($pckName, $dbTable, @primKey);

Creates a new Perl class of name $pckName that represents a database table. That class inherits from DBIx::DataModel::Table. If $pckName contains no ::, then the schema name is prepended to it (so the new table class is created in the namespace of the schema). $dbTable should contain the name of the table in the database. @primKey should contain the name of the column (or names of columns) holding the primary key for that table.

View

  MySchema->View($viewName, $columns, $dbTables, \%where, @parentTables);

Creates a new Perl class of name $viewName that represents a SQL SELECT request of shape

  SELECT $columns FROM $dbTables [ WHERE %where ]

Therefore arguments $columns and $dbTables should be strings; the optional \%where argument should be a hashref, as explained below.

If $viewName or any parent table name contains no ::, then the schema name is prepended to it.

View() is seldom called explicitly from client code; it is mainly useful internally for implementing the "join" method. However, it could also be used to build queries with specific SQL clauses like for example

  MySchema->View(MyView =>
     "DISTINCT column1 AS c1, t2.column2 AS c2",
     "Table1 AS t1 LEFT OUTER JOIN Table2 AS t2 ON t1.fk=t2.pk",
     {c1 => 'foo', c2 => {-like => 'bar%'}},
     qw/Table1 Table2/);

The class generated by View() has a select() method, which will

  • select records from the database according to the criteria of the view, merged with the criteria of the request;

  • apply the 'fromDB' handlers of the parent tables to those records;

  • bless the results into objects of $viewName.

See SQL::Abstract for a complete description of what to put in the \%where argument. For the moment, just consider the following example:

  my $lst = MySchema::MyView->select(-where => {c3 => 22});

This would generate the SQL statement:

  SELECT DISTINCT column1 AS c1, t2.column2 AS c2
  FROM  Table1 AS t1 
        LEFT OUTER JOIN Table2 AS t2 ON t1.fk=t2.pk
  WHERE (c1 = 'foo' AND c2 LIKE 'bar%' AND c3 = 22)

The \%where argument can of course be undef.

The optional list of @parentTables contains names of Perl table classes from which the view will also inherit. If the SQL code in $dbTables is a join between several tables, then it is a good idea to mention these tables in @parentTables, so that their role methods become available to instances of MySchema::MyView>. Be careful about table names : the SQL code in $dbTables should contain database table names, whereas the members of @parentTables should be Perl table classes (might be the same, but not necessarily).

Perl views as defined here have nothing to do with views declared in the database itself. Perl views are totally unknown to the database, they are just abstractions of SQL statements. If you need to access database views, just use the Table declaration, like for a regular table.

Association

  MySchema->Association([$class1, $role1, $multiplicity1, @columns1], 
                        [$class2, $role2, $multiplicity2, @columns2]);

Declares an association between two tables (or even two instances of the same table), in a UML-like fashion. Each side of the association specifies its table, the "rolename" of of this table in the association, the multiplicity, and the name of the column or list of columns that technically implement the association as a database join.

Role names should preferably be chosen so as to avoid conflicts with column names in the same table.

Multiplicities should be written in the UML form '0..*', '1..*', '0..1', etc. (minimum .. maximum number of occurrences); this will influence how role methods and views are implemented, as explained below. The '*' for "infinite" may also be written 'n', i.e. '1..n'. Multiplicity '*' is a shortcut for '0..*', and multiplicity '1' is a shortcut for '1..1'. Other numbers may be given as multiplicity bounds, but this will be just documentary : technically, all that matters is

  • whether the lower bound is 0 or more (if 0, generated joins will be left joins, otherwise inner joins)

  • whether the upper bound is 1 or more (if 1, the associated method returns a single object, otherwise it returns an arrayref)

If @columns1 or @columns2 are omitted, they are guessed as follows : for the table with multiplicity 1 or 0..1, the default is the primary key; for the other table, the default is to take the same column names as the other side of the association. This default behaviour is convenient for data models where primary keys and foreign keys are identical (for example dpt_id both as primary key in Department and as foreign key in Activity). Some data models have a different policy, where primary keys are always named the same (for example id), and foreign keys are named after the related table name : in such models, the default does not work, and you have to specify the join columns explicitly.

Roles as additional methods in table classes

As a result of the association declaration, the Perl class $table1 will get an additional method named $role2 for accessing the associated object(s) in $table2; that method normally returns an arrayref, unless $multiplicity2 has maximum '1' (in that case the return value is a single object ref). Of course, $table2 conversely gets a method named $role1.

To understand why tables and roles are crossed, look at the UML picture :

  +--------+                     +--------+
  |        | *              0..1 |        |
  | Table1 +---------------------+ Table2 |
  |        | role1         role2 |        |
  +--------+                     +--------+

so from an object of Table1, you need a method role2 to access the associated object of Table2. In your diagrams, be careful to get the role names correctly according to the UML specification. Sometimes we see UML diagrams where role names are on the wrong side, mainly because modelers have a background in Entity-Relationship or Merise methods, where it is the other way around.

Role methods perform joins within Perl (as opposed to joins directly performed within the database). That is, given a declaration

  MySchema->Association([qw/Employee   employee   1   /],
                        [qw/Activity   activities 0..*/]);

we can call

  my activities = $anEmployee->activities

which will implicitly perform a

  SELECT * FROM Activity WHERE emp_id = $anEmployee->{emp_id}

The role method can also accept additional parameters in SQL::Abstract format, exactly like the select() method. So for example

  my $activities = $anEmployee->activities(-columns => [qw/act_name salary/],
                                           -where   => {is_active => 'Y'});

would perform the following SQL request :

  SELECT act_name, salary FROM Activity WHERE 
    emp_id = $anEmployee->{emp_id} AND
    is_active = 'Y'

If the role method is called without any parameters, and if that role was previously expanded (see expand() method), i.e. if the object hash contains an entry $obj->{$role}, then this data is reused instead of calling the database again (this is a primitive form of caching). To force a new call to the database, supply some parameters :

  $emp->expand('activities');  # stores result in $emp->{activities}
  $list = $emp->activities;    # returns cached $emp->{activities}
  $list = $emp->activities(-columns => '*');  # default columns, but 
                                              # forces a new call to the DB

Sometimes associations are unidirectional (it does not make sense to traverse the association in both directions). In such cases, just supply 0 or an empty string (or even the string "0" or '""' or -- or "none") to one of the role names : then the corresponding role method is not generated.

Methods insert_into_...

When a role has multiplicity '*', another method named insert_into_... is also installed, that will create new objects of the associated class, taking care of the linking automatically :

  $anEmployee->insert_into_activities({d_begin => $today, 
                                       dpt_id  => $dpt});

This is equivalent to

  MySchema::Activity->insert({d_begin => $today, 
                              dpt_id  => $dpt, 
                              emp_id  => $anEmployee->{emp_id}});

Many-to-many associations

UML conceptual models may contain associations where both roles have multiplicity '*' (so-called many-to-many associations). However, when it comes to actual database implementation, such associations need an intermediate linking table to collect couples of identifiers from both tables.

DBIx::DataModel supports many-to-many associations as a kind of syntactic sugar, translated into low-level associations with the linking table. The linking table needs to be declared first :

  MySchema->Table(qw/link_table link_table prim_key1 prim_key2/);

  MySchema->Association([qw/table1     role1  0..1/],
                        [qw/link_table links    * /]);

  MySchema->Association([qw/table2     role2  0..1/],
                        [qw/link_table links    * /]);

This describes a diagram like this :

  +--------+               +-------+                 +--------+
  |        | 0..1        * | Link  | *          0..1 |        |
  | Table1 +---------------+  --   +-----------------+ Table2 |
  |        | role1  linksA | Table | linksB    role2 |        |
  +--------+               +-------+                 +--------+

Then we can declare the many-to-many association, very much like ordinary associations, except that the last items in the argument lists are names of roles to follow, instead of names of columns to join. In the diagram above, we must follow roles linksA and role2 in order to obtain the rows of Table2 related to an instance of Table1; so we write

  MySchema->Association([qw/table1  roles1  *  linksB role1/],
                        [qw/table2  roles2  *  linksA role2/]);

which describes a diagram like this :

              +--------+                    +--------+
              |        | *                * |        |
              | Table1 +--------------------+ Table2 |
              |        | roles1      roles2 |        |
              +--------+                    +--------+

The declaration has created a new method roles2 in Table1; that method is implemented by following roles linksA and role2. So for an object obj1 of Table1, the call

  my $obj2_arrayref = $obj1->roles2();

will generate the following SQL :

  SELECT * FROM link_table INNER JOIN table2
            ON link_table.prim_key2=table2.prim_key2
    WHERE link_table.prim_key1 = $obj->{prim_key1}

Observe that roles2() returns rows from a join, so these rows will belong both to Table2 and to Link_Table.

Many-to-many associations do not have an automatic insert_into_* method : you must explicitly insert into the link table.

Following multiple associations

In the previous section we were following two roles at once in order to implement a many-to-many association. More generally, it may be useful to follow several roles at once, joining the tables in a single SQL query. This can be done through the following methods :

  • "join" (invoked on a Schema) : create a new View that selects from several tables, filling the joins automatically

  • "join" (invoked on an instance of Table or View) : from a given object, follow a list of roles to get information from associated tables.

  • "MethodFromJoin" : add a new method in a table, that will follow a list of roles (shortcut for repeated calls to join).

Composition

  MySchema->Composition([$class1, $role1, $multiplicity1, @columns1], 
                        [$class2, $role2, $multiplicity2, @columns2]);

Declares a composition between two tables, i.e an association with some additional semantics. In UML class diagrams, compositions are pictured with a black diamond on one side : this side will be called the composite class, while the other side will be called the component class. In DBIx::DataModel, the diamond (the composite class) corresponds to the first arrayref argument, and the component class corresponds to the second arrayref argument, so the order of both arguments is important (while for associations the order makes no difference).

The UML intended meaning of a composition is that objects of the component classes cannot exist outside of their composite class. Within DBIx::DataModel, the additional semantics for compositions is to support cascaded insertions and deletions and auto-expansion :

  • the argument to an insert may contain references to subrecords. The main record will be inserted in the composite class, and within the same operation, subrecords will be inserted into the component classes, with foreign keys automatically filled with appropriate values.

  • the argument to a delete may contain lists of component records to be deleted together with the main record of the composite class.

  • roles declared through a Composition may then be supplied to AutoExpand() so that the composite class can automatically fetch its component parts.

See the documentation of insert(), delete() and AutoExpand() methods below for more details.

Note that compositions add nothing to the semantics of update operations.

Even though the arguments to a Composition look exactly like for Association, there are some more constraints : the maximum $multiplicity1 must be 1 (which is coherent with the notion of composition), and the maximum $multiplicity2 must be greater than 1 (because one-to-one compositions are not common and we don't know exactly how to implement cascaded inserts or deletes in such a case). Furthermore, a class cannot be component of several composite classes, unless the corresponding multiplicities are all 0..1 instead of the usual 1.

join

join as class method within a Schema

  my $view = MySchema->join($table, $role1, $role2, ..);

Creates a View class, starting from a given table class and following one or several associations through their role names. It calls the "View" method, with a collection of parameters automatically inferred from the associations. So for example

  MySchema->join(qw/Department activities employee/);

is equivalent to

  my $sql = <<_EOSQL_
  Department 
    LEFT OUTER JOIN Activity ON Department.dpt_id = Activity.dpt_id
    LEFT OUTER JOIN Employee ON Activity.emp_id   = Employee.emp_id
  _EOSQL_
  
  MySchema->View(DepartmentActivitiesEmployee => '*', $sql, 
                 qw/Department Activity Employee/);

For each pair of tables, the kind of join is chosen according to the multiplicity declared with the role : if the minimum multiplicity is 0, the join will be LEFT OUTER JOIN; otherwise it will be a usual inner join (exception : after a first left join, all remaining tables are also connected through additional left joins). The default kind of join chosen by this rule may be overriden by inserting pseudo-roles in the list, namely '<=>' or INNER for inner joins and '=>' or LEFT for left joins. So for example

  MySchema->join(qw/Department <=> activities <=> employee/);

becomes equivalent to

  my $sql = <<_EOSQL_
  Department 
    INNER JOIN Activity ON Department.dpt_id = Activity.dpt_id
    INNER JOIN Employee ON Activity.emp_id   = Employee.emp_id
  _EOSQL_

Table names in the SQL statement correspond to what was defined in the MySchema->Table(...) declarations. However, tables may be aliased using | as a separator :

  MySchema->join(qw/Department|dpt activities|act employee|emp/)
          ->select(-columns => qw/dpt.name act.d_begin emp.lastname/,
                   -where   => {"dpt.dpt_name" => {-like => "A%"}});

which generates

  SELECT dpt.name, act.d_begin, emp.lastname
  FROM Department AS dpt
    LEFT OUTER JOIN Activity AS act ON dpt.dpt_id = act.dpt_id
    LEFT OUTER JOIN Employee AS emp ON act.emp_id = emp.emp_id
  WHERE dtp.dpt_name like 'A%'

All tables participating in a join are stacked, and further roles are found by walking up the stack. So in

  ..->join(qw/FirstTable role1 role2 role3/)

we must find a role1 in FirstTable, from which we know what will be the Table2. Then, we must find a role2 in in Table2, or otherwise in FirstTable, in order to know Table3. In turn, role3 must be found either in Table3, or in Table2, or in FirstTable, etc. To resolve ambiguities, prefix the role by the role name or alias of the targeted source, such as :

  ..->join(qw/FirstTable role1|r1 FirstTable.role2 r1.role3|r3 role2.role4/)

The resulting view name will be composed by concatenating the table and the capitalized role names. If join kinds were explicitly set, these also belong to the view name, like Department_INNER_Activities. Since such names might be long and uncomfortable to use, the view name is also returned as result of the method call, so that the client code can store it in a variable and use it as an alias.

The main purpose of join is to gain efficiency in interacting with the database. If we write

  foreach my $dpt (@{MySchema::Department->select}) {
    foreach my $act ($dpt->activities) {
      my $emp = $act->employee;
      printf "%s works in %s since %s\n", 
         $emp->{lastname}, $dpt->{dpt_name}, $act->{d_begin};
    }
  }

many database calls are generated behind the scene. Instead we could write

  my $view = MySchema->join(qw/MySchema::Department activities employee/);
  foreach my $row (@{$view->select}) {
    printf "%s works in %s since %s\n", 
      $row->{lastname}, $row->{dpt_name}, $row->{d_begin};
  }

which generates one single call to the database.

join as class method within a Table or View

  my $statement = My::Table->join(qw/role1 role2 .../)->prepare;

Starting from a given table, returns a reference to a statement that selects a collection of data rows from associated tables, performing the appropriate joins. Internally this is implemented throught the Schema::join method, with an additional join criteria to constrain on the primary key(s) of My::Table. That statement cannot be executed yet, because the values of the primary key are not known until we have an instance of My::Table; but the statement can already be prepared. Later on, we can execute the statement by binding it to an instance of My::Table :

   my $obj = My::Table->fetch(...);
   my $rows = $statement->execute($obj)->all;

join as instance method within a Table or View

Creates a statement as just explained above, and immediately binds it to the current object. So for example if $emp->{emp_id} == 987, then

  $emp->join(qw/activities department/)
      ->select(-where => {d_end => undef})

will generate

  SELECT * FROM Activity INNER JOIN Department 
                         ON Activity.dpt_id = Department.dpt_id
           WHERE  emp_id = 987 AND d_end IS NULL

MethodFromJoin

  $table->MethodFromJoin($meth_name => qw/role1 role2 .../, \%options);

Inserts into the table class a new method named $meth_name, that will automatically call join() and then select(), passing its arguments to the select call. This is useful for joining several tables at once, so for example with

  MySchema::Department
    ->MethodFromJoin(employees => qw/activities employee/);

we can then write

  my $empl_ref = $someDept->employees(-where   => {gender => 'F'},
                                      -columns => [qw/firstname lastname]);

This method is used internally to implement many-to-many associations; so if you have only two roles to follow, you would probably be better off by defining the association, which is a more abstract notion. Direct calls to MethodFromJoin are still useful if you want to follow three or more roles at once.

The last argument to MethodFromJoin is an optional hashref; if present, the hash will be passed as initial argument to the select call.

SCHEMA OR TABLE PARAMETERIZATION

DefaultColumns

  My::Table->DefaultColumns($columns);

Sets the default value for the -columns argument to select(). If nothing else is stated, the default value for all tables is '*'.

ColumnHandlers

  My::Table->ColumnHandlers($columnName => handlerName1 => coderef1,
                                           handlerName2 => coderef2, ...);

Associates some handlers to a given column in the current table class. Then, when you call $obj->applyColumnHandler('someHandler'), each column having a handler of the corresponding name will execute the associated code. This can be useful for all sorts of data manipulation :

  • converting dates between internal database format and user presentation format

  • converting empty strings into null values

  • inflating scalar values into objects

  • column data validation

Handlers receive the column value as usual through $_[0]. If the value is to be modified (for example for scalar conversions or while inflating values into objects), the result should be put back into $_[0]. In addition to the column value, other info is passed to the handler :

  sub myHandler {
    my ($columnValue, $obj, $columnName, $handlerName) = @;
    my $newVal = $obj->computeNewVal($columnValue, ...);
    $columnValue = $newVal; # WRONG : will be a no-op
    $_[0] = $newVal;        # OK    : value is converted
  }

The second argument $obj is the object from where $columnValue was taken -- most probably an instance of a Table or View class. Use this if you need to read some contextual information, but avoid modifying $obj : you would most probably get unexpected results, since the collection of available columns may vary from one call to the other.

Other arguments $columnName and $handlerName are obvious.

Handler names fromDB and toDB have a special meaning : they are called automatically just after reading data from the database, or just before writing into the database. Handler name validate is used by the method hasInvalidColumns().

ColumnType

  MySchema->ColumnType(type_name => handler_name1 => coderef1,
                                    handler_name2 => coderef2, ...);

When invoked on a schema, declares a collection of column handlers under name type_name.

  My::Table->ColumnType(type_name => qw/column1 column2 .../);

When invoked on a table, retrieves all column handlers defined under type_name in the schema and calls ColumnHandlers() to register those handlers to column1, column2, etc.

Autoload

  MySchema->Autoload(1);   # turn on AUTOLOAD 
  My::Table ->Autoload(1); # turn it on, just for one table

If Autoload is turned on, then columns have implicit read accessors through Perl's AUTOLOAD mechanism. So instead of $record->{column} you can write $record->column. This feature is off by default, because the hashref API $record->{column} is the recommended way to access data when using DBIx::DataModel.

Caveat : AUTOLOAD is a global feature, so if there are several schemas, MySchema->Autoload(1) actually turns it on for all of them.

AutoInsertColumns

  MySchema->AutoInsertColumns( columnName1 => sub{...}, ... );
  My::Table->AutoInsertColumns( columnName1 => sub{...}, ... );

Declares handler code that will automatically fill column names columnName1, etc. at each insert, either for a single table, or (if declared at the Schema level), for every table. For example, each record could remember who created it and when with something like

  MySchema->AutoInsertColumns( created_by => 
    sub{$ENV{REMOTE_USER} . ", " . localtime}
  );

The handler code will be called as

  $handler->(\%record, $table)

so that it can know something about its calling context. In most cases, however, the handler will not need these parameters, because it just returns global information such as current user or current date/time.

AutoUpdateColumns

  MySchema->AutoUpdateColumns( columnName1 => sub{...}, ... );
  My::Table->AutoUpdateColumns( columnName1 => sub{...}, ... );

Just like AutoInsertColumns, but will be called automatically at each update and each insert. This is typically used to remember the author and/or date and time of the last modification of a record. If you use both AutoInsertColumns and AutoUpdateColumns, make sure that the column names are not the same.

When doing an update (i.e. not an insert), the handler code will be called as

  $handler->(\%record, $table, \%where)

where %record contains the columns to be updated and %where contains the primary key (column name(s) and value(s)).

NoUpdateColumns

  MySchema->NoUpdateColumns(@columns);
  My::Table->NoUpdateColumns(@columns);

Defines an array of column names that will be excluded from INSERT/UPDATE statements. This is useful for example when some column are set up automatically by the database (like automatic time stamps or user identification). It can also be useful if you want to temporarily add information to memory objects, without passing it back to the database.

NoUpdate columns can be set for a whole Schema, or for a specific Table class.

AutoExpand

  My::Table->AutoExpand(qw/role1 role2 .../)

Generates an autoExpand() method for the class, that will autoexpand on the roles listed (i.e. will call the appropriate method and store the result in a local slot within the object). In other words, the object knows how to expand itself, fetching information from associated tables, in order to build a data tree in memory. Only roles declared as Composition() may be auto-expanded.

Be careful about performance issues: when an object uses auto-expansion through a call to autoExpand(), every auto-expanded role will generate an additional call to the database. This might be slow, especially if there are recursive auto-expansions; so in some cases it will be more appropriate to flatten the tree and use database joins, typically through the method join().

RUNTIME PROPERTIES OR PARAMETERIZATION

dbh

  my $dbh = DBI::connect(...);
  MySchema->dbh($dbh, %options);        # set

  my $dbh             = MySchema->dbh;  # get back just the dbh
  my ($dbh, %options) = MySchema->dbh;  # get back all

Returns or sets the handle to a DBI database handle (see DBI). This handle is schema-specific. DBIx::DataModel expects the handle to be opened with RaiseError => 1 (see "Transactions and error handling").

In %options you may pass any key-value pairs, and retrieve them later by calling dbh in a list context. DBIx::DataModel will look in those options to try to find the "catalog" and "schema" arguments for DBI's last_insert_id.

Changing the database handle through the dbh method is forbidden while a transaction is in course. However, a nested transaction may temporarily change the database handle by supplying it as argument to the "doTransaction" method.

schema

  $schema = $class->schema;
  $schema = $object->schema;

Returns the name of the schema class for the given object or class (table or view).

db_table

  $db_table = $class->db_table;
  $db_table = $object->db_table;

Returns the database table name registered via Schema->Table(..) or collection of joined tables registered via Schema->View(..).

debug

  Schema->debug( 1 );            # will warn for each SQL statement
  Schema->debug( $debugObject ); # will call $debugObject->debug($sql)
  Schema->debug( 0 );            # turn off debugging

Debug mode is useful for seeing SQL statements generated by DBIx::DataModel. Enabling debugging with a $debugObject will typically be useful in conjunction with something like Log::Log4perl or Log::Dispatch.

There is also another way to see the SQL code :

  my $spy_sql = sub {my ($sql, @bind) = @_;
                     print STDERR join "\n", $sql, @bind;
                     return ($sql, @bind);};
  
  my $result = $myClassOrObj->$someSelectMethod(-columns  => \@columns,
                                                -where    => \%criteria,
                                                -postSQL  => $spy_sql);

classData

  my $val = $someClass ->classData->{someKey};
  my $val = $someObject->classData->{someKey};

Returns a ref to a hash for storing class-specific data. Each subclass has its own hashref, so class data is NOT propagated along the inheritance tree. Class data should be mainly for reading; if you write into it, make sure you know what you are doing.

primKey

  my @primKeyColumns = My::Table->primKey;
  my @primKeyValues  = $obj->primKey;

If called as a class method, returns the list of columns registered as primary key for that table (via Schema->Table(..)).

If called as an instance method, returns the list of values in those columns.

When called in scalar context and the primary key has only one column, returns that column (so you can call $my k = $obj->primKey).

componentRoles

  my @roles = My::Table->componentRoles;

Returns the list of roles declared through Composition().

noUpdateColumns

  my @cols = MySchema->noUpdateColumns;

Returns the array of column names declared as noUpdate through NoUpdateColumns().

  my @cols = $obj->noUpdateColumns;

Returns the array of column names declared as noUpdate, either in the Schema or in the Table class of the invocant.

autoUpdateColumns

  my @cols = MySchema->autoUpdateColumns;

Returns the array of column names declared as autoUpdate through AutoUpdateColumns().

  my @cols = $obj->autoUpdateColumns;

Returns the array of column names declared as autoUpdate, either in the Schema or in the Table class of the invocant.

selectImplicitlyFor

  MySchema->selectImplicitlyFor('read only'); # will be added to SQL selects
  MySchema->selectImplicitlyFor('');          # turn it off

Gets or sets a default value for the -for argument to select(). Here it is set at the Schema level, so it will be applied to all tables.

  $tableClass->selectImplicitlyFor('read only');
  $viewClass->selectImplicitlyFor('');

Same thing, but at a Table or View level.

  my $string = $object->selectImplicitlyFor;

Retrieves whatever whas set in the table or in the schema.

dbiPrepareMethod

  MySchema->dbiPrepareMethod('prepare_cached');

DBI statement handles will be created using "prepare_cached" in DBI.

tables

   my @tables = MySchema->tables;

Returns an array of names of Table subclasses declared in this schema.

views

   my @views = MySchema->views;

Returns an array of names of View subclasses declared in this schema.

localizeState

  {
    my $scope_guard = MySchema->localizeState;
    # or..
    my $scope_guard = MySchema->localizeState(qw/dbh dbh_options 
                                                 selectImplicitlyFor/);
    ... # do some work, possibly change state
  
  } # $scope_guard out of scope : previous state of MySchema is restored 

Schema classes hold some global state (database connection, current debug mode, current value of selectImplicitlyFor, etc.). Like for other global resources (for example STDIN or %ENV), this could create interferences if the global state is simultaneously modified by several independent components.

The usual Perl solution to this kind of problem is dynamic scoping through local (see "Temporary Values via local" in perlsub). Here however, since local is not perfectly suited for private class data, we provide a solution which is similar in spirit, but slightly different in implementation. The localizeState method internally takes a copy of the current state, and returns a handle to it. The handle should be stored in a my variable; when that variable goes out of scope (at block exit), then the previous state is restored.

If called without arguments, localizeState localizes the following state components by default : dbh, dbh_options, debug, selectImplicitlyFor, dbiPrepareMethod, statementClass. Otherwise, the list of specific components to localize can be passed in the argument list.

statementClass

  MySchema->statementClass($classname);

Dynamically sets the statement class. It is quite uncommon to change it after schema initialization, but may nevertheless be useful in specific cases like for example if the dbh switches from one kind of database to another.

DATA RETRIEVAL AND MANIPULATION

doTransaction

  my $coderef = sub {Table1->insert(...); Table2->update(...); ...};
  MySchema->doTransaction($coderef);

Evaluates the code within a transaction. In case of failure, the transaction is rolled back, and an exception is raised with the error message and the status of the rollback (because the rollback itself may also fail).

Usually the coderef passed as argument will be a closure that may refer to variables local to the environment where the closure was created.

Nested calls to doTransaction are supported : only the top-level call will actually initiate and then commit the transaction, while an exception at any level will abort and rollback the whole thing.

If the nested transaction needs to work on a different database handle, it may do so by supplying the dbh and its options as additional arguments :

  MySchema->doTransaction($coderef, $new_dbh, %new_dbh_options);

When called in this form, doTransaction will temporarily set the dbh to the supplied value, and then return to the previous value when the nested transaction is finished. Commits on all involved database handles are delayed until the top-level transaction is finished.

fetch

  my $record = My::Table->fetch(@keyValues, \%options);

Fetches a single record from a table, from its primary key value. %options may specify things like -for, -preExec, -postExec, etc.

This method is just syntactic sugar for

  my $record = My::Table->select(-fetch => \@keyValues, %options);

(see below).

fetch_cached

  my $record = My::Table->fetch_cached(@keyValues, \%options);

Like fetch, except that the result is stored in a cache, and further calls to the same methods with the same parameters will return the cached record instead of going back to the database. The cache does not know about any updates to the database, so this is mainly useful for readonly data.

The cache is stored internally in MyTable->classData->{fetch_cached}{$dbh_addr}{$freeze_args} (where $dbh_addr is Scalar::Util::refaddr(MyTable->dbh) and $freeze_args is Storable::freeze(@keyValues, \%options)). Using these arguments, the cache can be cleared or tied to a caching module.

createStatement

  my $statement = My::Table->createStatement;

Creates a statement that will search the target table (or view). The statement can then be refined, sqlized, prepared and finally executed (see DBIx::DataModel::Statement).

select

Given a $target, which could be either a table, a view or a statement :

  $records = $target->select(\@columns, \%where, \@order);
  
  $records = $target->select(-columns     => \@columns, 
                             # OR : -distinct => \@columns,
                             -where       => \%where,
                             # OR : -fetch => $key,
                             # OR : -fetch => \@key,
                             -groupBy     => \@groupings,
                             -having      => \%criteria,
                             -orderBy     => \@order,
                             -for         => 'read only',
                             -postSQL     => \&postSQL_callback,
                             -preExec     => \&preExec_callback,
                             -postExec    => \&preExec_callback,
                             -postFetch   => \&postFetch_callback,
                             -limit       => $limit,
                             -offset      => $offset,
                             -pageSize    => $pageSize,
                             -pageIndex   => $pageIndex,
                             -columnTypes => \%columnTypes,
                             -resultAs  => 'rows'      || 'firstrow' 
                                        || 'flat_arrayref'
                                        || 'sth'       || 'sql'
                                        || 'statement' || 'fast_statement');
  
  $all_records = $target->select();

Applies a SQL SELECT to the $target, and returns a result as specified by the -resultAs argument (see below).

If $target is a table or a view, select is just an alias to $target->createStatement->select(...).

Arguments are all optional and may be passed either by name or by position (but you cannnot combine both positional and named arguments in a single call). Positional arguments should be considered as deprecated; named arguments are recommended because they are much more readable and offer a richer set of options.

Named arguments to select()

-columns => \@columns

\@columns is a reference to an array of SQL column specifications (i.e. column names, * or table.*, functions, etc.).

A '|' in a column is translated into an 'AS' clause, according to the current SQL dialect: this is convenient when using perl qw/.../ operator for columns, as in

  -columns => [ qw/table1.longColumn|t1lc table2.longColumn|t2lc/ ]

Column aliasing should be avoided on key columns (either primary or foreign keys), because role methods will no longer be able to navigate through the joins (currently DBIx::DataModel is not clever enough to rename its internal join constraints according to column aliases). Aliasing on non-key columns is OK, and column handlers will operate properly on aliased columns.

The argument to -columns can also be a string instead of an arrayref, like for example "c1 AS foobar, MAX(c2) AS m_c2, COUNT(c3) AS n_c3"; however this is mainly for backwards compatibility. The recommended way is to use the arrayref notation as explained above :

  -columns => [ qw/  c1|foobar   MAX(c2)|m_c2   COUNT(c3)|n_c3  / ]

If omitted, \@columns takes the default, which is usually '*', unless modified through DefaultColumns().

No verification is done on the list of retrieved \@columns, so the list does not have to include the primary or foreign keys --- but then later attempts to perform joins or updates will obviously fail.

-distinct => \@columns

behaves like the -columns arguments, except that keyword DISTINCT will be included in the generated SQL.

-where => \%where

\%where is a reference to a hash or array of criteria that will be translated into SQL clauses. In most cases, this will just be something like {col1 => 'val1', col2 => 'val2'}; see SQL::Abstract::select for detailed description of the structure of that hash or array. It can also be a plain SQL string like "col1 IN (3, 5, 7, 11) OR col2 IS NOT NULL".

-fetch => \@columns

equivalent to

  ...->select(-where => {<primary_key_column0> => $columns[0],
                         <primary_key_column1> => $columns[1], ...},
              -resultAs => "firstrow")

If the primary key ranges on one single column (which is the most frequent case), then the argument to -fetch can also be a single scalar value :

  ...->select(-fetch => $key)

When calling a table directly, the select(-fetch => ..) syntax is awkward; you will most certainly prefer the syntactic sugar offered by the fetch() method :

  My::Table->fetch(@key)

However, the -fetch notation is useful when walking through association roles :

  $employee->activities(-fetch => $act_id)

This example will generate the following SQL

  SELECT * FROM activity WHERE act_id=$act_id AND emp_id=$employee->{emp_id}

Notice how this is different from

  MySchema::Activity->fetch($act_id)

which would generate

  SELECT * FROM activity WHERE act_id=$act_id

Both examples would end up with the same record, but in the first case there is an additional check that this record really belongs to the given employee.

In presence of -fetch, arguments -where and -selectAs are not allowed.

-groupBy => "string" or -groupBy => \@array

adds a GROUP BY clause in the SQL statement. Grouping columns are specified either by a plain string or by an array of strings.

-having => "string" or -having => \%criteria

adds a HAVING clause in the SQL statement (only makes sense together with a GROUP BY clause). This is like a -where clause, except that the criteria are applied after grouping has occured.

-orderBy => \@order

\@order is a reference to a list of columns for sorting. It can also be a plain SQL string like "col1 DESC, col3, col2 DESC". Columns can also be prefixed by '+' or '-' for indicating sorting directions, so for example -orderBy => [qw/-col1 +col2 -col3/] will generate the SQL clause ORDER BY col1 DESC, col2 ASC, col3 DESC.

-for => $clause

specifies an additional clause to be added at the end of the SQL statement, like -for => 'read only' or -for => 'update'.

-postSQL => \&postSQL_callback

hook for specifying a callback function to be called on SQL code and bind values, before preparing the statement. It will be called as follows:

  ($sql, @bind) = $args->{-postSQL}->($sql, @bind) if $args->{-postSQL};
-preExec => \&preExec_callback, -postExec => \&postExec_callback

hooks for specifying callback functions to be called on the DBI statement handle, just before or just after invoking execute(). So the sequence will be more or less like this:

  $sth = $dbh->prepare($sql_statement);
  $preExec_callback->($sth)  if $preExec_callback;
  $sth->execute(@bind_values);
  $postExec_callback->($sth) if $postExec_callback;

This is mostly useful if you need to call driver-specific functions at those stages.

-postFetch => \&postFetch_callback

hook for specifying a callback function to be called on data rows. The callback will be called after blessFromDB, i.e. the row is already an object of the proper class and column handlers have been applied.

-pageSize => $pageSize

specifies how many rows will be retrieved per "page" of data. Default is unlimited (or more precisely the maximum value of a short integer on your system). When specified, automatically implies -limit.

-pageIndex => $pageIndex

specifies the page number (starting at 1). Default is 1. When specified, automatically implies -offset.

-limit => $limit

limit to the number of rows that will be retrieved. Automatically implied by -pageSize.

-offset => $offset

Automatically implied by -pageIndex.

-columnTypes => \%columnTypes

dynamically specifies some column types at the statement level. Usually column types are defined within tables at compile time, but it may be necessary to defined additional types within the statement, for example when using database functions and/or aliases. The argument is a hashref in which keys are names of column types defined within the schema, and values are arrayrefs of column names :

   select(-columns     => [qw/ MAX(date_col)|max_date 
                               MIN(date_col)|min_date ... /],
          -columnTypes => { Date => [qw/max_date min_date/] },
          ...)
-resultAs => $result_kind

specifies what kind of result will be produced. The result is always a scalar and does not depend on the calling context. Possible result kinds are :

rows

The result will be a ref to an array of rows, blessed into objects of the class. This is the default result kind. If there are no data rows, a ref to an empty list is returned.

firstrow

The result will be just the first data row, blessed into an object of the class. If there is no data, undef is returned.

flat_arrayref

The result will be a ref to an array that concatenates results from each row. Usually this is combined with a -distinct or -columns argument with one single column, to get a vertical slice from a resultset, like in

  my $all_names = MySchema::People->select(-distinct => [qw/firstname/],
                                           -resultAs => 'flat_arrayref');
  print sort @$all_names;

However, it may also be used for example to fill a hash from pairs retrieved from each row, like in

  my $pairs = MySchema::People->select(-columns  => [qw/pers_id firstname/],
                                       -resultAs => 'flat_arrayref');
  my %hash = @$pairs;

Finally, it can be convenient to avoid column aliases when using aggregator functions :

  my $array_ref = $source->select(-columns => [qw/MAX(col1)
                                                 AVG(col2)
                                                 COUNT(DISTINCT(col3))/],
                                  -where    => ...,
                                  -resultAs => 'flat_arrayref');
  my ($max_col1, $avg_col2, $count_col3) = @$array_ref;
statement

The result will be an instance of DBIx::DataModel::Statement. That object has a next method that fetches the next datarow and blesses it into the appropriate object, or returns undef when there is no more data to fetch. So a typical usage pattern is :

  my $statement = $class->select(-where    => \%criteria, 
                                 -resultAs => 'statement');
  while (my $row = $statement->next) {
    do_something_with($row);
  }

If called with an argument, the next method returns an array ref of several rows, as in

 my $rows = $statement->next(10);

Finally, the statement also has an all method that returns an arrayref of all remaining rows.

When creating a new Schema, a different statement class can be specified via the statementClass argument. For example the DBIx::DataModel::Statement::JDBC subclass in this distribution is intended for DBD::JDBC data sources, and gives access to some JDBC methods over the statement (for example positioning instructions).

fast_statement

The result is like a normal statement, except that rows are successively fetched into the same memory location, using DBI's fetch and bind_columns methods. This is the fastest way to get data; however, pay attention to this warning from DBI's documentation : Note that the same array reference is returned for each fetch, so don't store the reference and then use it after a later fetch. Also, the elements of the array are also reused for each row, so take care if you want to take a reference to an element. Furthermore, any field added into the row will remain present for the next rows.

Of course it is not possible to call all or next(10) on a fast statement.

sth

The result will be an executed DBI statement handle. Then it is up to the caller to retrieve data rows using the DBI API. If needed, these rows can then be blessed into appropriate objects through blessFromDB().

sql

In scalar context, the result will just be the generated SQL statement. In list context, it will be ($sql, @bind), i.e. the SQL statement together with the bind values.

subquery

Returns an arrayref containing [\"($sql)", @bind]. This is in anticipation for the future version of SQL::Abstract (coming soon) where we will be able to write something like

  my $subquery = $source1->select(..., -resultAs => 'subquery');
  my $rows     = $source2->select(
      -columns => ...,
      -where   => {foo => 123, bar => {-not_in => $subquery}}
   );

Positional arguments to select()

Positional arguments to select() are deprecated -- use named arguments, as described above.

The API for positional arguments is mostly borrowed from SQL::Abstract. Some clever inspection of arrayrefs and hashrefs is performed in order to guess which argument is intended for what :

  ...->select(\@foo, \%bar, \@buz);
  #    select(-columns => \@foo, -where => \%bar, -orderBy => \@buz);
  
  ...->select($foo, $bar);
  #    select(-columns => $foo, -where => $bar)
  
  ...->select(\%foo, \@bar);
  #    select(-where => \%foo, -orderBy => \@bar);
  
  ...->select(\%foo, $bar);
  #    select(-where => \%foo, -orderBy => $bar);

  ...->select(\%foo, \@bar, \@buz);
  #    ERROR

unbless

  MySchema->unbless($obj1, $obj2, ...);

Recursively applies "damn" in Acme::Damn to removes all class information from its arguments : these become plain Perl hashrefs, arrayrefs or scalars.

This may be useful if the datatree returned by a select(..) / expand(..) needs to be exported through an external module that only considers plain datastructures; this is the case for example with "Dump" in YAML::Syck.

insert

  my @ids = My::Table->insert({col1 => $val1, col2 => $val2, ...}, 
                              {...});

Applies the toDB handlers, removes the noUpdate columns, and then inserts the new records into the database. Because of the handlers, this operation may modify the argument data, so it is not safe to access $val1, $val2, etc. after the call.

Primary key column(s) should of course be present in the supplied hashrefs, unless the the key is auto-generated.

Each hashref will be blessed into the MyTable class, and will be inserted through the internal _singleInsert() method. The default implementation of this method should be good enough for most common uses, but you may want to refine it in your table classes if you need some fancy handling on primary keys (like for example computing a random key and checking whether that key is free).

Scalar values returned by _singleInsert() are collected into an array, and then returned by insert(); usually, these are the primary keys of the inserted records (if on one single column). In scalar context, the return value is the first id in the list above, which makes sense if you call insert() with a single argument. If you call it with several arguments but from a scalar context, a warning is issued.

If the table is a composite class (see Composition() above), then the component parts may be supplied within the hashref, with keys equal to the role names, and values given as arrayrefs of sub-hashrefs; then these will be inserted into the database, at the same time as the main record, with join values automatically filled in. For example :

   HR::Employee->insert({firstname  => "Johann Sebastian",  
                         lastname   => "Bach",
                         activities => [{d_begin  => '01.01.1695',
                                         d_end    => '18.07.1750',
                                         dpt_code => 'CPT'}]});

update

  My::Table->update({col1 => $val1, ...});
  My::Table->update(@primKey, {col1 => $val1, ...});
  $obj->update;

This is both a class and an instance method. It applies the toDB handlers, removes the noUpdate columns, and then updates the database for the given record.

When called as a class method, the columns and values to update are supplied as a hashref. The second syntax with @primKey is an alternate way to supply the values for the primary key (it may be more convenient because you don't need to repeat the name of primary key columns). So if emp_id is the primary key of table Employee, then the following are equivalent :

  HR::Employee->update({emp_id => $eid, 
                        address => $newAddr, 
                        phone => $newPhone});
  HR::Employee->update($eid => {address => $newAddr, 
                                phone => $newPhone});

When called as an instance method, i.e.

  $someEmployee->update;

the columns and values to update are taken from the object in memory (ignoring all non-scalar values). After the update, the memory for that object is emptied (to prevent any confusion, because the 'toDB' handlers might have changed the values). So to continue working with the same record, you must fetch it again from the database (or clone it yourself before calling update).

In either case, you have no control over the 'where' clause of the SQL update statement, that will be based exclusively on primary key columns. So if you need to simultaneously update several records with a SQL request like

  UPDATE myTable SET col='newVal' WHERE otherCol like 'criteria%'

then you should generate the SQL yourself and pass it directly to DBI->do($sql).

The update method only updates the columns received as arguments : it knows nothing about other columns that may sit in the database table. Therefore if you have two concurrent clients doing

  (client1)  My::Table->update($id, {c1 => $v1, c2 => $v2});
  (client2)  My::Table->update($id, {c3 => $v3, c4 => $v4, c5 => $v5});

the final state of record $id in the database will reflect changes from both clients.

delete

  My::Table->delete({column1 => value1, ...});
  My::Table->delete(@primKey);
  $record->delete;

This is both a class and an instance method. It deletes a record from the database.

When called as a class method, the primary key of the record to delete is supplied either as a hashref, or directly as a list of values. Note that My::Table->delete(11, 22) does not mean "delete records with keys 11 and 22", but rather "delete record having primary key (11, 22)"; in other words, you only delete one record at a time. In order to simultaneously delete several records according to some WHERE criteria, you must generate the SQL yourself and go directly to the DBI level.

When called as an instance method, the primary key is taken from object columns in memory. After the delete, the memory for that object is destroyed. If the table is a composite class (see Composition() above), and if the object contains references to lists of component parts, then those will be recursively deleted together with the main object (cascaded delete). However, if there are other component parts in the database, not referenced in the hashref, then those will not be automatically deleted : in other words, the delete method does not go by itself to the database to find all dependent composite parts (this is the job of the client code, or sometimes of the database itself).

applyColumnHandler

  $class ->applyColumnHandler($handlerName, \@objects);
  $object->applyColumnHandler($handlerName);

Inspects the target object or list of objects; for every column that exists in the object, checks whether a handler named $handlerName was declared for that column (see method "ColumnHandlers"), and if so, calls the handler. By this definition, if a column is absent in an object, then the handler for that column is not called, even though it was declared in the class.

The results of handler calls are collected into a hashref, with an entry for each column name. The value of each entry depends on how applyColumnHandlers was called : if it was called as an instance method, then the result is something of shape

  {columnName1 => resultValue1, columnName2 => resultValue2, ... }

if it was called as a class method (i.e. if \@objects is defined), then the result is something of shape

  {columnName1 => [resultValue1forObject1, resultValue1forObject2, ...], 
   columnName2 => [resultValue2forObject1, resultValue2forObject2, ...], 
   ... }

If columnName is not present in the target object(s), then the corresponding result value is undef.

hasInvalidColumns

  my $invalid_columns = $obj->hasInvalidColumns;
  if ($invalid_columns) {
    print "wrong data in columns ", join(", ", @$invalid_columns);
  }
  else {
   print "all columns OK";
  }

Applies the 'validate' handler to all existent columns. Returns a ref to the list of invalid columns, or undef if there are none.

Note that this is validation at the column level, not at the record level. As a result, your validation handlers can check if an existent column is empty, but cannot check if a column is missing (because in that case the handler would not be called).

Your 'validate' handlers, defined through "ColumnHandlers", should return 0 or an empty string whenever the column value is invalid. Never return undef, because we would no longer be able to distinguish between an invalid existent column and a missing column.

expand

  $obj->expand($role [, @args] )

Executes the method $role to follow an Association, stores the result in the object itself under $obj->{$role}, and returns that result. This is typically used to expand an object into a tree datastructure. Optional @args are passed to $obj->$role(@args), for example for specifying -where, -columns or -orderBy options.

After the expansion, further calls to $obj->$role (without any arguments) will reuse that same expanded result instead of calling again the database. This caching improves efficiency, but also introduces the risk of side-effects across your code : after

  $obj->expand(someRole => (-columns => [qw/just some columns/],
                            -where   => {someField => 'restriction'}))

further calls to $obj->someRole() will just return a dataset restricted according to the above criteria, instead of a full join. To prevent that effect, you would need to delete $obj->{someRole}, or to call the role with arguments : $obj->someRole('*').

autoExpand

  $record->autoExpand( $recurse );

Asks the object to expand itself with some objects in foreign tables. Does nothing by default. Should be redefined in subclasses, most probably through the "AutoExpand" method (with capital 'A'). If the optional argument $recurse is true, then autoExpand is recursively called on the expanded objects.

blessFromDB

  $class->blessFromDB($record);

Blesses $record into an object of the table or view class, and applies the fromDB column handlers.

DEPRECATED METHODS

Here are some deprecated methods from previous versions

  • ViewFromRoles is now called "join" (class method in Schema)

  • selectFromRoles is now called "join" (instance method in Source)

  • MethodFromRoles is now called "MethodFromJoin" (class method in Source)

  • selectSth is now writen select(..., resultAs => "sth")

  • SqlDialect is now expressed as argument to Schema()

  • applyColumnHandlers is now called applyColumnHandler

  • keepLasth and lasth are no longer needed; if you want to interact with the database statement handle, use the DBIx::DataModel::Statement API.

  • preselectWhere is no longer needed (superseded by the Statement::refine method).