[CDBI] after_set_$col and after_create

Kate Yoak kate at longmedia.com
Wed Oct 26 02:15:23 BST 2005

OK, So there is a bit of a philosophic disagreement.  I decided to go ahead
and address the points in the hope that it is a useful one.  :-)

> > The statemtnt
> >
> > my $foo=Foo->create({first=>"hello", second=>"world"});
> >
> > is basically equivalent to
> >
> > my $foo = Foo->create();
> > $foo->set(first=>"hello", second=>"world");
> > $foo->update();
> The key there is 'basically'. Inserting and updating are 2 different
> things. If they are different, then there needs to be a way for the
> programmer to do something different for each.
> This mimics what most databases with real triggers do.

In the cases above, the difference is not update vs. insert.  The difference
logically is, put all the values in at once, or do them as they come.

The implication of the name after_set_value is that it's something you are
going to want to do each time a value is set.  The fact that create()
doesn't happen to use set internally is a surprise - something one can only
discover by looking at the internals of Class::DBI.  Few people would assume
that it doesn't happen to use set() method to set the values.  The choice of
implementation isn't necessarily wrong, but it's not obvious.

> > with the exception of some performance considerations.  In general, we
> > chosse one form over the other depending on the desired flow of
> execution,
> > efficiency, etc.
> That's not really true. We choose create()/INSERT when we have a new
> record, and update()/UPDATE when we have an exising record.

Looking at the examples above, both create a new record.  The only question
is the timing of parameter assignment.  If you think back to logical
programming outside of Class::DBI, you can see the paradigm all the time.
Most modules enable the user to provide the parameters in the constructor,
or alternatively by using mutators.

It is true that Class::DBI puts you into a somewhat different world where
you have to think about the fact that you are tied to the database and
ignoring it will cause problems, this is not one of the effects of being
tied to the database.  The topic of discussion is closer to OO design than a
database-specific issue.

In other words, new Foo {age =>13 } should generally behave the same as
Foo->age(13) with the exception of assignment order, which a developer needs
to keep in mind.

> > Foo->add_trigger(after_set_first => sub {shift()->flag(1) });
> >
> > This trigger will only be executed in the second example above
> - when we are
> > using set() to place the values into the record, rather than create -
> > Class::DBI::create() does not use set, nor calls after_set_ triggers.
> >
> > To fix this, we may add a before_create trigger that checks if we are
> > setting the column and calls the same function.
> >
> > Now everything works as it should.  However, the default
> behavior seems off
> > as the developer has to make sure all the after_set (or
> before_set) triggers
> > are duplicated elsewhere.
> If the duplication really bothers you, you can do something like:
> sub _flag_this { shift()->flag(1) };
> Foo->add_trigger(before_set_first => \&_flag_this);
> Foo->add_trigger(before_create_first => \&_flag_this);

I like this solution, except I wasn't aware of before_create_$col trigger.
Nor do I see it in Class::DBI code.

More information about the ClassDBI mailing list