Seitenanfang

Data::ObjectDriver and JOIN

Data::ObjectDriver is a great ORM. It's easy to configure and easy to use, but not as powerful as DBIx::Class (which isn't that easy to learn and I actually prefer using a wrapper instead of "native" DBIx::Class, but that's another story). There is one major thing I missed with Data::ObjectDriver: JOINing foreign tables.

But today I discovered that at least relations are supported pretty good, even better than with DBIx::Class. Data::Objectdriver defines every table as one class, like this:

package MyProject::DB::Cars;
use base qw( Data::ObjectDriver::BaseObject );

__PACKAGE__->install_properties({
columns => [ 'plate_id', 'color', 'manufacturer', 'model', ],
datasource => 'cars',
primary_key => [ 'plate_id', ],
driver => MyProject::DB::Driver->driver,
});

This is the table-class Cars, located in the Project's namespace structure. I prefer to locate class modules in a dedicated project namespace tree (or place) instead of placing them at the topmost level without any ::.

A car is pretty useless without someone sitting on the front left (or right, depending on your country) seat:

package MyProject::DB::Drivers;
use base qw( Data::ObjectDriver::BaseObject );

__PACKAGE__->install_properties({
columns => [ 'id', 'firstname', 'lastname', 'car_plate_id', ],
datasource => 'drivers',
primary_key => [ 'id', ],
driver => MyProject::DB::Driver->driver,
});

Don't mix up the "Drivers" controlling a car with the DB::Driver used to connect the database!

I need a dump sample to demonstrate foreign keys in Data::ObjectDriver and I'll define that each driver will only drive one car but some drivers share the same car. It takes only a short definition with the the Drivers class to connect both:

__PACKAGE__->has_a(
{ class => 'MyProject::DB::Cars', column => 'car_plate_id', parent_method => "drivers_objs", }
);

Each driver has a car now, not only within the database, but also within the objects created by Data::ObjectDriver. A new method is added to each Drivers object, called car_plate_obj. It returns the appropriate car object used by this driver. The optional setting cached => 1 would cache the car object within the drivers object. Without cached mode, each call of the car_plate_obj would do a fresh database access to return the car object. The car object itself got a drivers_objs method which returns the objects for all drivers using this car.

car_plate_obj is not that good as method name, it could be easily overwritten using the method keyword:

__PACKAGE__->has_a(
{ class => 'MyProject::DB::Cars', column => 'car_plate_id', method => 'car_obj', cached => 1, parent_method => "drivers_objs", }
);

Data::ObjectDriver will create a car_obj method now, which is much more handy.

Using foreign keys is possible in Data::ObjectDriver but still improvable. I didn't find a way to access the parent object by something else than the primary key and also nothing about loading all car which are driven by drivers called "Frank" as firstname value without loading the drivers, like a classic SQL JOIN would do.

 

1 Kommentar. Schreib was dazu

  1. Shmuel Fomberg

    How about something like:


    Car->load(undef, { join => Driver->join_on('car_plate_id', { firstname => 'Frank' }) } );

Schreib was dazu

Die folgenden HTML-Tags sind erlaubt:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>