2 DBIx::Class::ResultSource::MultipleTableInheritance -- Use multiple
3 tables to define your classes
7 package MyApp::Schema::Result::Coffee;
9 __PACKAGE__->table_class('DBIx::Class::ResultSource::MultipleTableInheritance');
10 __PACKAGE__->table('coffee');
11 __PACKAGE__->add_columns(
14 data_type => "integer",
15 default_value => "nextval('coffee_seq'::regclass)",
16 is_auto_increment => 1,
24 default_value => "good",
28 __PACKAGE__->set_primary_key("id");
34 package MyApp::Schema::Result::Sumatra;
38 __PACKAGE__->table('sumatra');
40 __PACKAGE__->add_columns(
44 default_value => undef,
54 my $schema = MyApp::Schema->connect($dsn);
56 my $cup = $schema->resultset('Sumatra')->new;
58 print STDERR Dumper $cup->columns;
64 Inherit from this package and you can make a resultset class from a
65 view, but that's more than a little bit misleading: the result is
66 writable and updateable--transparently.
68 This is accomplished through the use of stored functions that map
69 changes written to the view to changes to the underlying concrete
73 In many applications, many classes are subclasses of others. Let's say
76 # Conceptual domain model
91 That's redundant. Hold on a sec...
99 class Investor isa User {
103 Good idea, but how to put this into code?
105 One far-too common and absolutely horrendous solution is to have a
106 "checkbox" in your database: a nullable "investor" column, which entails
107 a nullable "dollars" column, in the user table.
109 create table "user" (
110 "id" integer not null primary key autoincrement,
111 "name" text not null,
112 "password" text not null,
113 "investor" tinyint(1),
117 Let's not discuss that further.
119 A second, better, solution is to break out the two tables into user and
122 create table "user" (
123 "id" integer not null primary key autoincrement,
124 "name" text not null,
125 "password" text not null
128 create table "investor" (
129 "id" integer not null references user("id"),
133 So that investor's PK is just an FK to the user. We can clearly see the
134 class hierarchy here, in which investor is a subclass of user. In
135 DBIx::Class applications, this second strategy looks like:
137 my $user_rs = $schema->resultset('User');
138 my $new_user = $user_rs->create(
139 name => $args->{name},
140 password => $args->{password},
145 my $new_investor = $schema->resultset('Investor')->create(
147 dollars => $args->{dollars},
150 One can cope well with the second strategy, and it seems to be the most
151 popular smart choice.
154 There is a third strategy implemented here. Make the database do more of
155 the work. It'll save us some typing and it'll make for more expressive
156 code. What if we could do this:
158 my $new_investor = $schema->resultset('Investor')->create(
159 name => $args->{name},
160 password => $args->{password},
161 dollars => $args->{dollars},
164 And have it Just Work? The user ( {name => $args->{name}, password =>
165 $args->{password} } ) should be created transparently, and the use of
166 either user or investor in your code should require no special handling.
167 Deleting and updating $new_investor should also delete or update the
170 It does. User and investor are both views, their concrete tables
171 abstracted away behind a set of rules and triggers. You would expect the
172 above DBIC create statement to look like this in SQL:
174 INSERT INTO investor ("name","password","dollars") VALUES (...);
176 But using MTI, it is really this:
178 INSERT INTO _user_table ("username","password") VALUES (...);
179 INSERT INTO _investor_table ("id","dollars") VALUES (currval('_user_table_id_seq',...) );
181 For deletes, the triggers fire in reverse, to preserve referential
182 integrity (foreign key constraints). For instance:
184 my $investor = $schema->resultset('Investor')->find({id => $args->{id}});
189 DELETE FROM _investor_table WHERE ("id" = ?);
190 DELETE FROM _user_table WHERE ("id" = ?);
193 Matt S. Trout, <mst@shadowcatsystems.co.uk>
196 Docs: Amiri Barksdale, <amiri@metalabel.com>
199 This library is free software; you can redistribute it and/or modify it
200 under the same terms as Perl itself.
203 DBIx::Class DBIx::Class::ResultSource