[Dbix-class] RE: Inheritance question..

Oleg Pronin syber.rus at gmail.com
Thu Jan 22 01:39:38 GMT 2009


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 r=
ow 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 SQL.
    The idea is:

      package BaseClass;
      ->load_components(qw/DynamicSubclass FrozenColumns Core/);
      ->add_columns(qw/all_columns_that_are_common_to_all_subclasses + type
+ 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 obje=
ct
> 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 Foo
> 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 th=
en
> 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, NoisyFoo
> 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 transp=
arent
> 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 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/d6a=
f5d88/attachment-0001.htm


More information about the DBIx-Class mailing list