[Dbix-class] Relations on non in_storage rows (my todays gotcha)

luke saunders luke.saunders at gmail.com
Sun May 11 20:01:38 BST 2008


On Sun, May 11, 2008 at 5:48 PM, Zbigniew Lukasiak <zzbbyy at gmail.com> wrote:
> On Sun, May 11, 2008 at 4:34 PM, Matt S Trout <dbix-class at trout.me.uk> wrote:
>> On Sun, May 11, 2008 at 12:06:54PM +0200, Zbigniew Lukasiak wrote:
>>> If you have a new object, not yet in the database, like:
>>>
>>> $new_cd = $schema->resultset("CD")->new( {} );
>>>
>>> Then if you call $new_cd->artist - this will return a first artist in
>>> the 'artist' table.
>>
>> That's a bug, but the test we were given for it didn't work. Better test
>> case welcome and we can fix it.
>
> There is a strange test in 66relationship.t:
>
> my $undef_artist_cd = $schema->resultset("CD")->new_result({ 'title'
> => 'badgers', 'year' => 2007 });
> is($undef_artist_cd->has_column_loaded('artist'), '', 'FK not loaded');
> is($undef_artist_cd->search_related('artist')->count, 3, 'open search
> on undef FK');
>
> So it tests that a new row has 3 related artists - I cannot understand
> what that is supposed to mean.  I my opinion that count there should
> be 0.
>

It was me that made that change after a discussion with Matt.
Essentially the reasoning was that if the FK has not been set then an
open search is okay as anything could, in theory, be related.

> If we need another test then for example:
>
> my $new_cd = $schema->resultset("CD")->new( {} );
> is( $new_cd->search_related( 'artist' )->first, undef, 'No artist
> found for new cd' );
>
> Maybe I don't understand what is oing on here - but if my thinking is
> right and the test 'open search on undef FK' is wrong than the fix
> could be to change line 796 in lib/DBIx/Class/ResultSource.pm:
>
> -        $ret{$k} = $for->get_column($v) if $for->has_column_loaded($v);
> +        $ret{$k} = $for->get_column($v);

Yes, this was how it was before. When this was the case this code

  my $rel_object = $object->search_related($belongs_to_rel, { $fk =>
$value })->first;

would result in $rel_object being undef even if there was a related
row corresponding to $value - the SQL would look something like

  ... WHERE (PK IS NULL) AND (PK = $value);

This was causing problems with nested inserts as this test shows

  my $new_artist = $schema->resultset("Artist")->create({ artistid =>
18, name => 'larry' });

  eval {
    $schema->resultset("CD")->create({
              cdid => 28,
               title => 'Boogie Wiggle',
              year => '2007',
              artist => { artistid => 18, name => 'larry' }
             });
  };
  is($@, '', 'new cd created without clash on related artist');

With the old way the artist would be inserted twice as the
find_or_new_related for the second insert would not find the existing
artist with id 18, and this would of course cause a PK clash.

I have just added this test to t/96multi_create.t so that this bug
doesn't arise again if we revise the behaviour.

So that's the background to this problem. If the open search seems
unintuitive to people then probably we should revise/revert the
behaviour but we need to think about search_related and
find_or_new_related.



More information about the DBIx-Class mailing list