Open lifinsky opened 6 months ago
Current possible solution: Add interceptor on #[Before(pointcut: CommandHandler::class)], that takes the command with an entity id, then uses the repository to find the entity and returns the same or a different command instance, but with the entity instead of the id.
Can you provide PR with failing scenario?
Hi. I will add code snippets describing the problem. After clear all existing in database entities doctrines are perceived as new and their insertion and binding occurs, instead of just binding to the aggregate
So the case is that when we've main Entity (Aggregate Root) like Post
and we change it's child Entities Tag
, those child Entities won't be saved in database. And this is because we've not have not called ->persist(Tag)
on each of them, so Doctrine does not know that they are meant to be saved.
@lifinsky do I understand the problem correctly?
No, existing tag was saved but as new record (doctrine allows cascade: ['persist']):
// ObjectManagerInterceptor
foreach ($managerRegistries as $managerRegistry) {
/** @var EntityManagerInterface $objectManager */
foreach ($managerRegistry->getManagers() as $name => $objectManager) {
if (! $objectManager->isOpen()) {
$managerRegistry->resetManager($name);
}
if ($this->depthCount === 1) {
$objectManager->clear();
}
}
}
I think we should clear only agregates in unit of work. Entity manager supports clear($entityName = null) - null|string $entityName – if given, only entities of this type will get detached.
Currently for this example we should find tag in interceptor with pointcut "before" on CommandHandler (after transaction start)
So the problem is that we create Tag
Entity before outside of Post
Aggregate.
As Post Aggregate is created via Command, Unity of Work is cleared, therefore the reference to Tag
is also cleared.
This makes Doctrine ORM think this is new Entity, which need to be inserted instead of updated.
@lifinsky is this understanding correct?
Problem in using of existing entity, with current functionality of Ecotone we should inject tag repository to aggregate class or use command handler interceptor that find entity by id and fill attribute in command or return new command object (command is ugly with default arguments with null, for example int $tagId = null, Tag $tag = null. We should not clear entities in unit of work before command transaction
We should not clear entities in unit of work before command transaction
I think, it's fine to set up clearing after, as long as we can clean with each Message, we are good. Feel free to provide a PR with a test case you mentioned.
I'm running into this same issue. Did anything get sorted in the end as the last comment is quite a while ago and I can't find any related PR. Thanks
I'm running into this same issue. Did anything get sorted in the end as the last comment is quite a while ago and I can't find any related PR. Thanks
This issue is actual and not resolved
Description
In aggregates, it's possible to use, for instance, Doctrine entities with cascading persistence, but only for their insertion. Because ObjectManagerInterceptor clear object manager on transaction start.
Example
The only way to correctly save an aggregate with a one-to-many or many-to-many collection of entities is to inject the repository into the command handler of the aggregate or to use a "Before" interceptor that adds entities into the command before passing it to the handler.