note
siracusa
<blockquote><i>By writing the SQL myself I can write a single query that gives me exactly the results I need for almost anything. Class::DBI hits the database much harder and makes it shovel a lot more data back to the application for the same effect.</i></blockquote>
<p>Here's the sweet spot that I've settled on. I use an RDBMS-OO mapper for all the simple-to-medium-complexity things. This covers a lot, IME...say, 90%. For the more complex operations, I use custom SQL encapsulated by methods that sit right alongside my RDBMS-OO mapper's multi-object manipulation methods. In them, I pull all the table and column metadata from the RDBMS-OO mapper classes where it's already stored.</p>
<p>Here's what it looks like in action:</p>
<code>
# CRUD stuff:
$p = Product->new(id => 123);
$p->load;
$p->release_date->add(days => 1);
$p->save;
$p->delete;
# Multi-object operations
# Triple-join: one inner and two outer
$products =
Product::Manager->get_products(
require_objects => [ 'vendor' ],
with_objects => [ 'colors', 'categories' ]
query =>
[
name => { like => '%foo%' },
'vendor.billing_date' => { lt => DateTime->new(...) },
],
limit => 10,
offset => 50);
$num_deleted =
Product::Manager->delete_products(where => [ id => { gt => 100 } ]);
$num_updated =
Product::Manager->update_free_products(set => { price => 0.01 });
# Custom SQL operation
$num_pruned = Product::Manager->prune_products(type => 'all');
# Server-side SPL
$products = Product::Manager->get_popular_products(vendor_id => 123);</code>
<p>Without the comments, it's difficult to tell which operations are supported by the RDBMS-OO mapper, which required custom SQL under the covers, and which merely call through to server-side stored procedures.</p>
<p>And that's the point: to hide the implementation details behind a uniform interface to <i>all</i> database operations. There's also no SQL whatsoever in "end-user" code, and all the table and column names exist in a single place in the entire code base.</p>
<p>In all cases, I create the expected (although possibly sparsely populated) RDBMS-OO mapper objects before returning from the Manager methods. The number and nature of the db queries are almost always the limiting factors, so creating objects is not a big deal once all the data is available.</p>
<p>Each time a new database-manipulation operation needs to be defined, I have a choice. I can use my RDBMS-OO mapper directly, I can write some custom SQL, or I can write it in the database using SPL. No matter which I choose, the interface is the same. And I'm free to change my mind down the road, swapping implementations in the Manager as needed.</p>
<p>I find this approach vastly preferable to a series of DBI-style calls, even accounting for convenient modules like DBIx::Simple. YMMV, of course :)</p>
504724
504831