Skip Menu |

This queue is for tickets about the Rose-DB-Object CPAN distribution.

Report information
The Basics
Id: 100546
Status: rejected
Priority: 0/
Queue: Rose-DB-Object

People
Owner: Nobody in particular
Requestors: m.bunkus [...] linet-services.de
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: add_relname does not add object if relationship list is still undefined
Date: Tue, 25 Nov 2014 14:33:55 +0100
To: bug-Rose-DB-Object [...] rt.cpan.org
From: Moritz Bunkus <m.bunkus [...] linet-services.de>
Hey, We noticed this with a one-to-many relationship. Let's assume you have a customer with many contacts. The classes are named MyDB::Customer and MyDB::Contact, and inside MyDB::Customer there's the normal __PACKAGE__->add_relationship(…) with 'contacts' being the name. The problem is the following: my $customer = MyDB::Customer->new; $customer->add_contacts(MyDB::Contact->new); print scalar(@{ $customer->contacts || [] }); # this will output 0 After adding the contact the contact will not show up in $customer->contacts until you save the $customer. Instead $customer->contacts returns undef. The same happens with existing customers if you forcefully unset the relationship before: my $customer = MyDB::Customer->new; $customer->contacts(undef); $customer->add_contacts(MyDB::Contact->new); print scalar(@{ $customer->contacts || [] }); # this will output 0 You can circumvent the whole sharade if you forcefully set the relationship to an empty array reference. The first example now looks like this: my $customer = MyDB::Customer->new(contacts => []); $customer->add_contacts(MyDB::Contact->new); print scalar(@{ $customer->contacts || [] }); # this will output 1 This is extremely unpredictable behavior and makes working with RDBO as an object system pretty nasty; point in case: we've just spent roughly three hours digging through Rose's code in order to track down why it happens. The culprit seems to be the way Rose handles the local cache of add_on_save interfaces. As far as I can tell all new additions seem to be saved in a post-save hook in $self->{ON_SAVE_ATTR_NAME()}{post} and _additionally_ also in $self->{$key}, but only if that already exists. Since $self->{$key} will also get cleared when calling $obj->rel(undef), the add_on_save interface stops working there, too. Kind regards, Moritz Bunkus -- Dipl.-Inform. Moritz Bunkus Geschäftsführer/CTO LINET Services GmbH | Cyriaksring 10a | 38118 Braunschweig Tel. 0531-180508-0 | Fax 0531-180508-29 | http://www.linet-services.de LINET in den sozialen Netzwerken: https://twitter.com/linetservices | https://www.facebook.com/linetservices Wissenswertes aus der IT-Welt: http://www.linet-services.de/blog/ Geschäftsführung: Moritz Bunkus, Philip Reetz und Timo Springmann HR B 9170 Amtsgericht Braunschweig USt-IdNr. DE 259 526 516
Download signature.asc
application/pgp-signature 181b

Message body not shown because it is not plain text.

This behavior is correct. When you call an add_* method, an accurate representation of the full set of items requires knowing the existing set of items. If you set the existing items by calling the set method (e.g., by setting it to []) then the existing set of items is known (now empty) and the added items can be added to it directly. If the existing set of items is unknown, we can't just add items because then the relationship method(s) will return an incorrect population that does not include items from the set that existed before the addition.
Subject: Re: [rt.cpan.org #100546] add_relname does not add object if relationship list is still undefined
Date: Tue, 25 Nov 2014 16:27:29 +0100
To: bug-Rose-DB-Object [...] rt.cpan.org
From: Moritz Bunkus <m.bunkus [...] linet-services.de>
Hey, first of all thanks for replying so quickly. On Tuesday 25 November 2014 09:48:35 John Siracusa via RT wrote: Show quoted text
> This behavior is correct. When you call an add_* method, an accurate > representation of the full set of items requires knowing the existing set > of items.
… Granted, that explains why $obj->add_stuff(undef) acts like it does. However, if the object itself is brand new (MyDB::Class->new…) then there can be no set of existing items in the database and add_stuff() could simply create a new set of items. The existing set of items is known in that case: it's empty. The case that's more troubling to me is indeed the one with the new instance. For example, if I have some generic code that wants to add an element to an object no matter if the object is new or comes from the database then that code has to check whether or not the object is new and the relationship is still undef, if so, set the relationship to an empty array and call add_stuff() afterwards. Yes, we can do that, of course, but it's very, very surprising to the user of that code. Generic code that wants to use $obj->add_stuff() in a way that ensures that following code can simply access $obj->stuff() has to do these steps (pseudo-code): 1. If $obj is a new instance (think Rose::DB::Object::Util::is_in_db() is falsish): initialize with an empty array ref to force »yeah we know it's empty«: $obj->stuff([]) 2. Otherwise: read the relationship at least once in order to make sure that its state is not unknown anymore; $obj->stuff 3. Finally the $obj is sure about the state of the relationship and we can $obj->add_stuff() So please reconsider changing this behavior for the »new object« case at least. Thanks. Kind regards, Moritz -- Dipl.-Inform. Moritz Bunkus Geschäftsführer/CTO LINET Services GmbH | Cyriaksring 10a | 38118 Braunschweig Tel. 0531-180508-0 | Fax 0531-180508-29 | http://www.linet-services.de LINET in den sozialen Netzwerken: https://twitter.com/linetservices | https://www.facebook.com/linetservices Wissenswertes aus der IT-Welt: http://www.linet-services.de/blog/ Geschäftsführung: Moritz Bunkus, Philip Reetz und Timo Springmann HR B 9170 Amtsgericht Braunschweig USt-IdNr. DE 259 526 516
Download signature.asc
application/pgp-signature 181b

Message body not shown because it is not plain text.

On Tue Nov 25 10:27:53 2014, m.bunkus@linet-services.de wrote: Show quoted text
> Granted, that explains why $obj->add_stuff(undef) acts like it > does. However, if the object itself is brand new (MyDB::Class->new…) > then there can be no set of existing items in the database
That's not true. You could set the primary key column(s) on the newly constructed object at any time, making it an as-yet-un-load()ed incarnation of an existing database row.