philcrow has asked for the wisdom of the Perl Monks concerning the following question:

I'm having a bit of trouble with DBIx::Class. Though the problem seems like it should be common, my quick searches here and elsewhere didn't turn up anything obvious.

When I update a row and change a foreign key in it, the attribute is not being deleted, so I still get data from the old foriegn row. I've distilled this to the smallest example I could think of that would still make sense to me.

There are two tables as you can see from the explicit base model. One is for checks, the other is for their statuses. Each check has a foreign key which is a status.

package Check::Model; use strict; use warnings; use base 'DBIx::Class::Schema'; __PACKAGE__->load_classes( qw/ Check Status / ); 1;
The tables are also simple (note the belongs_to call in the Check model):
package Check::Model::Check; use base 'DBIx::Class'; __PACKAGE__->load_components( 'Core' ); __PACKAGE__->table( 'checks' ); __PACKAGE__->add_columns( qw/ id status descr / ); __PACKAGE__->set_primary_key( qw/ id / ); __PACKAGE__->belongs_to( status => 'Check::Model::Status' ); 1; package Check::Model::Status; use base 'DBIx::Class'; __PACKAGE__->load_components( 'Core' ); __PACKAGE__->table( 'status' ); __PACKAGE__->add_columns( qw/ id descr / ); __PACKAGE__->set_primary_key( qw/ id / ); 1;
With a little sqlite database in place, I can work on the database with this driving program:
#!/usr/bin/perl use strict; use warnings; use Check::Model; my $schema = Check::Model->connect( 'dbi:SQLite:dbname=checks', '', '' ); my $check = $schema->resultset('Check')->find( 1 ); my $status = $check->status->descr; print "status: $status\n"; # prints: 'status: Outstanding' $check->update( { status => 2 } ); $status = $check->status->descr; print "status: $status\n"; # also prints: 'status: Outstanding' $check = $schema->resultset( 'Check' )->find( 1 ); $status = $check->status->descr; print "status: $status\n"; # prints: 'status: Cleared'
If the check starts out with status 1, Outstanding, this will change the check to status 2, Cleared. That change is made in the database at the point of the update. But the second print still shows the old status description. By refetching the whole check, the third print shows the updated status description, which survives the program.

Dumping out the underlying objects shows that the foreign status ids are always correct, but that the hash for the foreign row remains unchanged through the update. I don't want to have to refetch just to clear the old foriegn row. Please tell me what I'm missing.

Phil

Replies are listed 'Best First'.
Re: DBIx::Class foreign key update woes
by castaway (Parson) on Jul 18, 2006 at 20:52 UTC
    Hi Phil,
    If you turn on SQL debugging (set DBIX_CLASS_STORAGE_DBI_DEBUG to true in your environment), you'll notice that the status object gets fetched when you first try to access ->descr, and isn't refetched when you just change a column entry in the check object. It would indeed be nice if that magically updated a related object, and I'll propose it.

    In the meantime you can do either:

    my $newstatus = $schema->resultset('Status')->find(2); $check->status($newstatus);
    or:
    $check->update({status => 2}); $check->discard_changes();
    It's not as pretty.. but it works.

    C.

      Thanks for the advice. It worked in my test.

      As for:

      It would indeed be nice if that magically updated a related object
      I don't need it to update that other object, just discard what it's holding so additional accesses will refetch it.

      Phil