ecotone-dev icon indicating copy to clipboard operation
ecotone-dev copied to clipboard

Provide the ability to use existing entities in commands for cascading persistence of state aggregate.

Open lifinsky opened this issue 1 year ago • 12 comments

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.

lifinsky avatar Mar 27 '24 19:03 lifinsky

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.

lifinsky avatar Mar 27 '24 21:03 lifinsky

Can you provide PR with failing scenario?

dgafka avatar Mar 28 '24 06:03 dgafka

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

lifinsky avatar Mar 28 '24 07:03 lifinsky

@dgafka https://gist.github.com/sushchyk/8ce3c718270f0ac75eb07264f899722a

lifinsky avatar Mar 28 '24 11:03 lifinsky

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?

dgafka avatar Mar 29 '24 07:03 dgafka

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.

lifinsky avatar Mar 29 '24 09:03 lifinsky

Currently for this example we should find tag in interceptor with pointcut "before" on CommandHandler (after transaction start)

lifinsky avatar Mar 29 '24 09:03 lifinsky

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?

dgafka avatar Mar 30 '24 08:03 dgafka

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

lifinsky avatar Mar 30 '24 09:03 lifinsky

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.

dgafka avatar Mar 30 '24 10:03 dgafka

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

benr77 avatar Jul 30 '24 16:07 benr77

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

lifinsky avatar Jul 30 '24 22:07 lifinsky