Slideshow transcript
Slide 1: Demystifying DBIx::Class Jay Shirley <jshirley@coldhardcode.com> http://our.coldhardcode.com/svn/DBIC-Beer
Slide 2: Mystic?
Slide 3: Why are ORMs scary?
Slide 4: Why are ORMs scary? • Enterprise-y
Slide 5: Why are ORMs scary? • Enterprise-y • Loss of control
Slide 6: Why are ORMs scary? • Enterprise-y • Loss of control • History (Class::DBI)
Slide 7: Why are ORMs scary? • Enterprise-y • Loss of control • History (Class::DBI) • (A triumph of multiple inheritance)
Slide 8: Retort.
Slide 9: Enterprise-y
Slide 10: Enterprise-y • Enterprise = Java
Slide 11: Enterprise-y • Enterprise = Java • DBIx::Class is written in perl
Slide 12: Loss of Control
Slide 13: Loss of Control • Still programmatic
Slide 14: Loss of Control • Still programmatic • Use SQL::Abstract rather than SQL
Slide 15: Loss of Control • Still programmatic • Use SQL::Abstract rather than SQL • Same thing
Slide 16: Loss of Control • Still programmatic • Use SQL::Abstract rather than SQL • Same thing • (except patches welcome)
Slide 17: Class::DBI
Slide 18: Class::DBI Sorry Schwern
Slide 19: Why DBIx::Class? • I like it. You’ll see why. • TIMTOWDI: • Rose::DB • Alzabo
Slide 20: Objects • Relations are only a third of an ORM
Slide 21: Objects • Relations are only a third of an ORM • What’s an object?
Slide 22: Objects • Relations are only a third of an ORM • What’s an object? • Database columns
Slide 23: Objects • Relations are only a third of an ORM • What’s an object? • Database columns • Table
Slide 24: Objects • Relations are only a third of an ORM • What’s an object? • Database columns • Table • Indexes
Slide 25: A Use Case
Slide 26: Beer
Slide 27: Yes, Beer.
Slide 28: Or... • Beer has many distributers • Beer has many reviews • Beer belongs to a brewer
Slide 29: Which means... package Beer::Schema::Beer; use base 'DBIx::Class'; __PACKAGE__->load_components( qw|Core| ); __PACKAGE__->table('beer'); __PACKAGE__->add_columns( 'pk1' => { data_type => 'integer', size => 16, is_nullable => 0, is_auto_increment => 1 }, 'name' => { data_type => 'varchar', size => 128, is_nullable => 0 }, 'brewer_pk1' => { data_type => 'integer', size => 16, is_nullable => 0, is_foreign_key => 1 }, ); __PACKAGE__->set_primary_key('pk1'); 1;
Slide 30: And indexes: __PACKAGE__->add_unique_index(...);
Slide 31: That gives you: • Deployable SQL (CREATE TABLE, etc) • The foundation for relationships: • $beer->brewer # DTRT
Slide 32: Managing Relations • A beer is: • made by a brewer • distributed by distributers • reviewed by people
Slide 33: Simple Relationships belongs_to is the opposite end of has_many
Slide 34: Simple Relationships belongs_to is the opposite end of has_many has_one, might_have means just that
Slide 35: Simple Relationships belongs_to is the opposite end of has_many has_one, might_have means just that many_to_many gets complicated
Slide 36: Creating a relation __PACKAGE__->belongs_to( ‘brewer’, # Accessor ‘Beer::Schema::Brewer’, # Related Class ‘brewer_pk1’ # My Column );
Slide 37: For simplicity... Brewers, Distributors and Beers are all easy All the same, except Beer has a brewer (brewer_pk1)
Slide 38: Using it (Manager) use Beer::Schema; my $schema = Beer::Schema ->connect( $dsn );
Slide 39: $schema # Fetch a result set my $rs = $schema->resultset(‘Beer’);
Slide 40: Result Sets # Everything is a result set. $rs->count; # How many Beers?
Slide 41: Everything is a Result Set $rs2 = $rs->search({ name => ‘Stout’ }); $rs2->count; # It chains together.
Slide 42: Chained Result Sets are what make DBIC Great
Slide 43: Result Sets return Result Sets $rs->search->search->search- >search->search->search ->search- >search->search->search->search- >search ->search->search->search- >search->search->search ->search- >search->search->search->search- >search ->search->search->search- >search->search->search ->search- >search->search->search->search- >search;
Slide 44: Why? $rs ->search({ $long_query }) ->search({ $more_filters }) ->search({ $even_more });
Slide 45: Actual Use: sub active_members { # All profiles that have purchased a membership. my $query = $rs->search( { 'purchase.saved_object_key' => 'membership', 'membership.expiration_date' => \\'>= NOW()' }, { join => { profile_transactions => { 'transaction' => { 'link_transaction_purchase' => { 'purchase' => 'membership' } } }, }, prefetch => [ 'state', 'country', { profile_transactions => { 'transaction' => { 'link_transaction_purchase' => { 'purchase' => 'membership' } } }, } ], group_by => [ qw/membership_id/ ] } ); }
Slide 46: In SQL: SELECT ... FROM table_profiles me LEFT JOIN profile_transaction profile_transactions ON ( profile_transactions.profile_id = me.profile_id ) JOIN nasa_transactions transaction ON ( transaction.transaction_id = profile_transactions.transaction_id ) LEFT JOIN link_trans_pp link_transaction_purchase ON ( link_transaction_purchase.transaction_id = transaction.transaction_id ) JOIN purchased_products purchase ON ( purchase.purchased_id = link_transaction_purchase.purchased_id ) JOIN nasa_membership membership ON ( membership.membership_id = purchase.saved_product_id ) JOIN state_lookup state ON ( state.state_lookup_id = me.state ) JOIN country_lookup country ON ( country.country_lookup_id = me.country_id ) WHERE ( membership.expiration_date >= NOW() AND purchase.saved_object_key = 'membership' )
Slide 47: Now: my $query = $schema->resultset(‘Profile’)->active_members; $query->count; # How many? $query->search({ first_name => ‘Bob’ }); # All matching members named Bob $query->search({ first_name => ‘Bob’ })->count; while ( my $profile = $query->next ) { $profile->cars; # Get all of this persons cars } # Clean, no ugly SQL
Slide 48: Pretty.
Slide 49: Even More: Managing your schema
Slide 50: Create Table Statements $schema->create_ddl_dir( [ 'SQLite', 'MySQL', ‘PostgreSQL’ ], $VERSION, \"$destination\" );
Slide 51: SQLite CREATE TABLE beer ( pk1 INTEGER PRIMARY KEY NOT NULL, name varchar(128) NOT NULL, brewer_pk1 integer(16) NOT NULL );
Slide 52: DROP TABLE IF EXISTS `beer`; MySQL -- -- Table: `beer` -- CREATE TABLE `beer` ( `pk1` integer(16) NOT NULL auto_increment, `name` varchar(128) NOT NULL, `brewer_pk1` integer(16) NOT NULL, INDEX (`pk1`), INDEX (`brewer_pk1`), PRIMARY KEY (`pk1`), CONSTRAINT `beer_fk_brewer_pk1` FOREIGN KEY (`brewer_pk1`) REFERENCES `brewer` (`pk1`) ON DELETE CASCADE ON UPDATE CASCADE ) Type=InnoDB;
Slide 53: PostgreSQL -- -- Table: beer -- DROP TABLE beer CASCADE; CREATE TABLE beer ( pk1 bigserial NOT NULL, name character varying(128) NOT NULL, brewer_pk1 bigint NOT NULL, PRIMARY KEY (pk1) );
Slide 54: Get a working database $schema->deploy; # Yes, it is this simple.
Slide 55: And now for tests



Add a comment on Slide 1
If you have a SlideShare account, login to comment; else you can comment as a guest- Favorites & Groups
Showing 1-50 of 0 (more)