[Dbix-class] object as a value of result_class (resultset_class)

Eden Cardim edencardim at gmail.com
Sun Sep 25 16:51:54 GMT 2011


>>>>> "Roman" == Roman Daniel <roman.daniel at davosro.cz> writes:

    Roman> Sorry, but your comment about maintenance nightmare is
    Roman> irrelevant.  Usually my column 'something' is called 'class'
    Roman> and is immutable. When I create the object I know whether I
    Roman> create Student or Worker. The example above can be rewritten
    Roman> as

    Roman> my $subclass = 'Me::Schema::Result::Person::'. $me->{class};
    Roman> return $subclass->inflate_result($result_source, $me,
    Roman> $prefetch);

    Roman> Also this approach is by no means mutually exclusive with
    Roman> your three tables, but it is complementing (I use extension
    Roman> tables, I have one for almost each 'class').

It's not mutually exclusive but it's also redudant and useless, besides
leaving more gaps for your system to become inconsistent during
runtime. If you already have a moniker for the class name, you might as
well canonize that to the name of the table implementing each specific
class. If the specialization of the row object doesn't involve data,
you'll be a lot better off using delegation for that, in fact, given
you're using a relational database, delegation is your best shot at
everything.

    Roman>  If I load the object from db and it is the instance of
    Roman> MySchema::Result::Person::Student, in application logic
    Roman> written in MySchema::Result::Person::Student I can use
    Roman> student relationship to other table, while in
    Roman> MySchema::Result::Person::Worker I will use worker
    Roman> relationship.

You should use a homogeneous relationship name in that case, call them
all "person", you might want to declare proxy methods, which is DBIC's
implementation of delegation, like this:

__PACKAGE__->belongs_to(
  person => 'MySchema::Result::Person'
         => { 'me.person_id' => 'foreign.id' }
         => { proxy => ['name', 'surname', etc... ] }
);

when you invoke $worker->name, it'll magically traverse the person
relationship and fetch the right data, same for $student->name. If you
need to optimize, add a prefetch to your queries on the specific tables.

    Roman> If you load MySchema::Result::Person instance from database
    Roman> how do you know which (mutually exclusive) relationship you
    Roman> should use? Here you have 2 of them, but when do you have 20
    Roman> types of person?

You don't, because polymorphism works by walking from specific classes
to generic classes, not the other way around. If you've made a
generalization, you're stuck at that level of the abstraction and you
can't assume anything about the more specific levels of the class
hierarchy.

The solution in practical terms is to not query the person table
directly, if you need the data from a lower level of the hierarchy. This
is analogous to not being able to create an instance of an abstract
class called Person in traditional class-based OO. If you need Person to
be a concrete class, whenever you load a person row, you're conceptually
stuck on that level of the hierarchy unless you somehow provide specific
information of what class you want to upgrade that object to. In
practical terms, you have to know what relationship you'll be using to
get to the specific data, because inheritance can only walk from a
specific class to a generic class.

    Roman> What are Neil's suggestions? I don't argue. Just give me the
    Roman> 2 lines of code clue about resultset processors.

You've been pointed to kiokudb twice, and I've detailed Neil's other
suggestion in this message and the previous one. To summarize, your
model is botched and you should fix it, otherwise you'll spend a fair
amount of time working around DBIC's ORM implementation.

-- 
  Eden Cardim
  Code Monkey                    http://www.shadowcat.co.uk/catalyst/
 Shadowcat Systems Ltd.  Want a managed development or deployment platform?
http://blog.edencardim.com/            http://www.shadowcat.co.uk/servers/
http://twitter.com/#!/edenc



More information about the DBIx-Class mailing list