Bug #36102
openIn 1:n relationships the parent might get lost
0%
Description
Given two classes that have a 1:n relationship modelled by means of a parent field in the child table like this:
class Parent { /** * @var Tx_Extbase_Persistence_ObjectStorage<Child> */ public $children; } class Child { /** * @var Parent */ public $parent; }
Updating the relationship can result in the child being stripped of its parent.
$newParent = $parentRepository->...; $child = $childRepository->...; $child->parent->children->remove($child), $newParent->children->add($child); $child->parent = $newParent;
This code sequence gives a consistent state in memory, but during persistAll()
, extbase will set the child's parent to NULL.
This is because extbase tries to be smart and to fix the parent field in case that the user didn't fully update the involved parties, but just added the child to its new parent.
In the above scenario, the objects are saved in this order$newParent
$child
$oldParent
- In
persistObjectStorage()
, called for$newParent
the parent field gets updated to the new parent uid. - In
persistObject()
for$child
the parent field gets updated to the new parent uid again. - In
persistObjectStorage()
for$oldParent
, the child is stripped of its parent by callingdetachObjectFromParentObject()
Thus the child becomes orphaned.
This can be worked around by means of calling persistAll()
yourself, because of another bug that causes ObjectStorages not to be marked as clean, thus they get persisted again when extbase calls persistAll()
itself, but this time the detaching won't happen, because the clean state of the parent object has been updated.
Updated by Marc Bastian Heinrichs over 12 years ago
Could you also post the tca of Parent children and Child parent, please?
It sounds more like an not supported relation type in T3 core than a bug in extbase.
Updated by Björn Steinbrink over 12 years ago
'parent' => array( 'config' => array( 'type' => 'select', 'foreign_table' => 'tx_extension_domain_model_parent', 'foreign_class' => 'Tx_Extension_Domain_Model_Parent', 'minitems' => 0, 'maxitems' => 1, ) )
and
'children' => array( 'exclude' => 1, 'config' => array( 'type' => 'inline', 'multiple' => 1, 'foreign_class' => 'Tx_Extension_Domain_Model_Child', 'foreign_table' => 'tx_extension_domain_model_child', 'foreign_field' => 'parent', 'foreign_sortby' => 'sorting', ) )
That the parent field is accessible doesn't even matter, it also fails if you just update the object storages for the children in the old and new parent, if things get persisted in the "wrong" order (the new parent is persisted first).
The use case is that I'm moving a child from one parent to another, that means that I either directly replace the parent, or that I first remove the parent and then set the new one. But extbase might as well end up first setting the new parent and then removing it.
A possible workaround might be to check that the child still has the old parent, and only unset its parent if that is the case, i.e. generate an update statement like
UPDATE tx_extension_domain_model_child SET parent = NULL WHERE parent = 123
But that could lead to other weird bugs in other cases, like this:
$oldParent->remove(child); $newParent->add(child); // somewhere else $child->setParent($oldParent);
If $oldParent
gets persisted last, the $child
would still end up without a parent.
Key in this example is that the in-memory state is inconsistent again. The two directions of the relationships don't match. IMHO extbase should just require that relationships are kept consistent in-memory (i.e. always update both sides), and then just persist the "parent" field, without trying to be smart. Having to keep it all in sync is the price one pays for using an object model instead of relational data.
Updated by Alexander Schnitzler about 12 years ago
- Assignee set to Alexander Schnitzler
- Target version set to Extbase 6.1
I guess we have to check if we have to rewrite the persistAll method and I guess we will not make it before 6.1.
Updated by Alexander Schnitzler over 11 years ago
- Status changed from New to Needs Feedback
Updated by Alexander Schnitzler over 11 years ago
- Target version changed from Extbase 6.1 to Extbase 6.2
Updated by Anja Leichsenring over 11 years ago
- Target version changed from Extbase 6.2 to Extbase 6.3
Updated by Alexander Schnitzler almost 11 years ago
- Assignee deleted (
Alexander Schnitzler)
Updated by Alexander Opitz about 10 years ago
- Project changed from 534 to TYPO3 Core
- Category deleted (
Extbase: Generic Persistence) - Status changed from Needs Feedback to New
- Target version deleted (
Extbase 6.3) - TYPO3 Version set to 6.2
- Is Regression set to No