[Dbix-class] RE: Inheritance question..

Oleg Pronin syber.rus at gmail.com
Thu Jan 22 11:25:02 GMT 2009


About aproxied args: exactly the same are done in DynamicSubclass but only
for frozen columns.

If you need to search subclass columns then you definetely need real
columns.

FrozenColumns need to prevent database overheat when you have many
subclassing columns because for example, mysql will spend a lot of time
adding new column to a table with 10mln records and will block it. This is
not acceptable for huge projects.

About custom resultsets for subclasses - this is a good idea i'll think of
it and probably add this functionality to DynamicSubclass.

2009/1/22 Howe, Tom (IDEAS PRACTICE AREAS) <Tom.Howe at morganstanley.com>

>
>  Hi Oleg,
> Thanks for your advice. I've tried this and it might be the way to go for
> me. Id prefer to be able to have a resultset object for the subclasses as
> well so that I can do $rs =3D $schema->resultset('ClassA')->new(...);
>
> That way it would ensure that the only the correct columns were available
> when creating a new row for classA.
>
> I would also be able to search on the subclass columns - why the need to
> use frozen columns, why cant you just use add_columns to add extra cols to
> the already defined baseclass ones for the subclass? Maybe this comes down
> to having just one result_source under the hood.
>
> I have managed via a custom resultset object to use set proxy methods at
> row creation by intercepting the new_result method.
>
> sub new_result {
>   my ($self, at args) =3D @_;
>
>   #get actual cols for the table
>   my @cols =3D $self->result_source->columns;
>
>   # look for provided args that are not in table
>   # assume they are proxied args
>   my %proxyArgs;
>    foreach my $k (keys %{$args[0]}) {
>       if (!grep /$k/, @cols) {
>         $proxyArgs{$k} =3D delete $args[0]{$k};
>      }
>   }
>   # create new row
>   my $row =3D $self->next::method(@args);
>
>   # set proxied args
>   foreach my $k (keys %proxyArgs) {
>     $row->$k($proxyArgs{$k});
>   }
> }
>
>
> with this in place, I can now do:
>
> $schema->resultset('SubClass')->create( subClassCol1=3D> 'xxx',
> subClassCol2=3D>'yyy', baseClassCol=3D> 'zzz');
>
> The subClassCol1 and subClassCol2 live in the sub class's table and the
> baseClassCol lives in the base class's Table.
> By this method I also ensure that a base class row exists for every sub
> class.
>
> I need to experiment more, but this should allow me to have Subclass and
> baseclass resultsets, both searchable on all columns. Just need to ensure=
 I
> can get the relationships correct to my other objects.
>
>
>  ------------------------------
> *From:* Oleg Pronin [mailto:syber.rus at gmail.com]
> *Sent:* 22 January 2009 01:40
> *To:* DBIx::Class user and developer list
> *Subject:* Re: [Dbix-class] RE: Inheritance question..
>
> 1) DBIx::Class::DynamicSubclass will automaticaly subclass your row object
> when
>      a) fetched from DB
>      b) created (->new or ->create)
>      c) changed subclassing column
>          For example when type =3D null row is BaseClass, when type =3D 1=
 row
> is ClassA, when 2 row is ClassB.
>          my $row =3D $rs->new({type =3D> 1}); # $row is ClassA
>          $row->type(2); #$row is ClassB
>          $row->type(undef); #$row is BaseClass
>
> 2) You can set up dynamic columns with subclassing if you use
> DBIx::Class::DynamicSubclass + DBIx::Class::FrozenColumns. But there is
> caveat: you will not be able to use 'frozen' columns in WHERE clause in S=
QL.
>     The idea is:
>
>       package BaseClass;
>       ->load_components(qw/DynamicSubclass FrozenColumns Core/);
>       ->add_columns(qw/all_columns_that_are_common_to_all_subclasses + ty=
pe
> + data/);
>       #data must be of type blob or text (depends on storage engine)
>       ->typecast_map(type =3D> {1 =3D> 'ClassA', 2 =3D> 'ClassB'});
>
>       package ClassA;
>       use parent 'BaseClass';
>       ->add_frozen|dumped|json_columns(data =3D>
> qw/all_columns_that_are_specific_to_ClassA    for_example/);
>
>       package MyCode;
>
>       my $row =3D $rs->create({type =3D> 1});
>       $row->for_example('hello'); #ok
>       $row->type(2);
>       $row->for_example('hello'); # error
>
>       $rs->new({ type=3D> 1, for_example =3D> 'hello' }); #that's ok too
>
> This is not ideal mechanism, but it quite useful and it helps me many
> times.
>
>
> 2009/1/21 Howe, Tom (IDEAS PRACTICE AREAS) <Tom.Howe at morganstanley.com>
>
>> Further to my question on inheritance, I have been trying subclassing and
>> the proxy method options and have a couple of other questions.
>>
>>
>> First, in an attempt to try the single flattened style where all Foo
>> object reside in one table, I tried the cookbook entry on "Dynamic
>> Sub-classing DBIx::Class proxy classes".
>>
>> I set up a db table called foo, created a Foo class with an
>> inflate_result() method and a Foo::Noisy class that inherited from the F=
oo
>> class.
>>
>> I can now create the Foo object and have it inflate into a Foo::Noisy
>> class.
>>
>> But, I cant get a Foo::Noisy resultset.
>>
>> I thought maybe I could define Foo with only the common columns, then
>> create a Foo::Noisy subclass that would inherit the columns of Foo and t=
hen
>> I could create a default value for 'type' and use add_columns() to define
>> the additional NoisyFoo column 'decibels'.
>>
>> But it seems the only resultset I can get is for Foo. So anyone creating
>> objects could inadvertently set a 'colour' for a NoisyFoo or a 'decibel'=
 for
>> ColouredFoo.
>>
>>
>>
>>
>>
>> The second thing I tried was to create 3 separate tables for Foo, NoisyF=
oo
>> and ColouredFoo. Then I created a Foo::Noisy class with a has_one
>> relationship to the Foo class using a proxy=3D>[] defined to allow trans=
parent
>> setting/getting of the 'name'.
>>
>> This works to a degree in that I can do :
>>
>> my $nf =3D $schema->resultset('Foo::Noisy')->create({id=3D>1, decibels=
=3D>110});
>> $nf->name('mynoisyfoo');
>>
>> But it fails if I try to do:
>> my $nf =3D $schema->resultset('Foo::Noisy')->create({id=3D>1, decibels=
=3D>110,
>> name=3D>'noisyfoo'});
>>
>> Giving the error:
>> DBIx::Class::ResultSet::create(): No such column name on DB::Foo::Noisy
>>
>> The proxy doesn't seem to be in affect during creation.
>>
>> Also, if I *don't* set the name, I don't get a row in the Foo table.
>> Is there a way to enforce that the row is created?
>>
>> Otherwise, if I want to search for all Foos, I cant do it on the common
>> table.
>>
>> Is there anyway to ensure the Foo row is created and grn can be passed on
>> create?
>>
>>
>>
>>
>>
>> > -----Original Message-----
>> > From: Howe, Tom (IDEAS PRACTICE AREAS)
>> > Sent: 21 January 2009 09:42
>> > To: DBIx::Class user and developer list
>> > Subject: [Dbix-class] Inheritance question..
>> >
>> > Class structure is something like this..
>> >
>>
>> +------+    +------------+              +-------------+
>> |  Bar |---o|  Relation  |o - - - - - - |     Foo     |abstract
>> +------+    +------------+              +-------------+class
>> |  id  |    |   attrs    |o             |      id     |
>> | name |    +------------+ \_________   |     name    |
>> +------+                    \        \  +-------------+
>>                             \        \___^_____    ^
>>                              \           |     \   |
>>                               \ +------------+  +-------------+
>>                                \|  NoisyFoo  |  | ColouredFoo |
>>                                 +------------+  +-------------+
>>                                 |     id     |  |     id      |
>>                                 |  decibels  |  |    color    |
>>                                 +------------+  +-------------+
>>
>> > +-------------+
>> >
>> > Bar has many Relations
>> > NoisyFoo has many Relations
>> > ColouredFoo has many Relations
>> > Bar many-many NoisyFoos
>> > Bar many-many ColouredFoos
>> >
>> > (Bar many-many Foos?)
>> >
>> >
>> > NoisyFoo and ColouredFoo inherit from Foo
>> >
>> > It actually gets more complicated than this because
>> > - Bar and Foo both inherit from a base object.
>> > - All objects have a unique id are connected via Relation objects
>> > - The relation object also contains levels of inheritance
>> >
>> > I want to be able to do queries like
>> >
>> > 1) Given a Bar, find all related Foo objs
>> > 2) Given a NoisyFoo or Coloured Foo, find all related Bars
>> > 3) For all bars with name matching "%str%" find all NoisyFoos
>> > with decibels > '100'
>> >
>> > Im not sure whether it would be better to
>> > a) retain Foo, NoisyFoo and ColouredFoo as a 3 separate tables,
>> > b) flatten to 2 tables, so NoisyFoo and ColouredFoo get their
>> > own name column
>> > c) flatten all Foos to 1 Foo table and create a Type column
>> > to differentiate.
>> >
>> >
>> > Questions:
>> >
>> >  Is it possible to create Foo, NoisyFoo and ColouredFoo as
>> > separate tables (a), then create corresponding DBIx proxy
>> > classes for them in such a way that when I create a new
>> > NoisyFoo row, the 'name' value is automatically entered into
>> > the Foo table? And when I retrieve the row it is
>> > automatically read in from the Foo table?
>> >
>> >
>> > If I were to flatten to 1 table per subclass (b), how would I
>> > write a relationship that enabled me to perform query (1)
>> > above; find all Foos for a given Bar.
>> > --------------------------------------------------------
>> >
>> > NOTICE: If received in error, please destroy and notify
>> > sender. Sender does not intend to waive confidentiality or
>> > privilege. Use of this email is prohibited when received in error.
>> >
>> > _______________________________________________
>> > List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
>> > IRC: irc.perl.org#dbix-class
>> > SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
>> > Searchable Archive:
>> > http://www.grokbase.com/group/dbix-class@lists.scsys.co.uk
>> >
>> --------------------------------------------------------
>>
>> NOTICE: If received in error, please destroy and notify sender. Sender
>> does not intend to waive confidentiality or privilege. Use of this email=
 is
>> prohibited when received in error.
>>
>> _______________________________________________
>> List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
>> IRC: irc.perl.org#dbix-class
>> SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
>> Searchable Archive:
>> http://www.grokbase.com/group/dbix-class@lists.scsys.co.uk
>>
>
>  ------------------------------
>
> NOTICE: If received in error, please destroy and notify sender. Sender do=
es
> not intend to waive confidentiality or privilege. Use of this email is
> prohibited when received in error.
>
> _______________________________________________
> List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
> IRC: irc.perl.org#dbix-class
> SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
> Searchable Archive:
> http://www.grokbase.com/group/dbix-class@lists.scsys.co.uk
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/dbix-class/attachments/20090122/34f=
654a9/attachment-0001.htm


More information about the DBIx-Class mailing list