5

考虑以下架构:

[Work]
id
tags ManyToMany(targetEntity="Tag", inversedBy="works", cascade={"persist"})

[Tag]
id
works_count
works ManyToMany(targetEntity="Work", mappedBy="tags")

works_count是一个计数器缓存Tag::works

我在WorkonFlush上有一个监听器,它检查是否已更改,并更新每个标签的.Work::tagsworks_count

public function onFlush(OnFlushEventArgs $args)
{
    foreach ($uow->getScheduledEntityUpdates() as $work) {
        $changedTags = /* update relevant tags and return all the changed ones */

        $metadata = $em->getClassMetadata('Acme\Entity\Tag');

        foreach ($changedTags as $tag) {
            $uow->recomputeSingleEntityChangeSet($metadata, $tag);
        }
    }
}

现在,如果我阅读更新标签的变更集,更改会works_count正确显示,它们不会在数据库中更新..

如果我替换recomputeSingleEntityChangeSet()为,computeChangeSet()那么一切都按预期工作并且数据库被更新,但是computeChangeSet()上面有一个@internal Don't call from the outside.注释,所以我不确定后果是什么..

互联网上的每个来源都说要使用recomputeSingleEntityChangeSet,那么为什么在这种情况下它不起作用?

PS 标签由 EntityManager 管理($em->contains($tag)返回 true)

4

4 回答 4

4

这个问题与 UnitOfWork 中的一个错误有关,最终在2014 年 9 月 11 日发布的Doctrine ORM 2.4.3中得到修复。有关详细信息,请参阅DDC-2996

于 2014-09-12T18:43:03.463 回答
3

看起来 Doctrine 2.2 可以合并变更集或生成新的变更集,但它需要知道哪个。如果你弄错了,它要么替换你现有的变更集,要么什么都不做。我很想知道是否有比这更好的选择,或者这是否正确。

    if($uow->getEntityChangeSet($entity)) {
        /** If the entity has pending changes, we need to recompute/merge. */
        $uow->recomputeSingleEntityChangeSet($meta, $contact);
    } else {
        /** If there are no changes, we compute from scratch? */
        $uow->computeChangeSet($meta, $entity);
    }
于 2014-05-09T07:31:48.363 回答
1

在原则 2.4.1 中,仅当您在事件侦听器中更改标签并且 UOW 包含标签 ChangeSet(发生在事件侦听器之外的更改)时,才使用 recomputeSingleEntityChangeSet。基本上 recomputeSingleEntityChangeSet 是一个为实体合并 ChangeSet 的函数。

来自函数的文档 传递的实体必须是托管实体。如果实体由于在提交周期中调用了此方法而已经具有更改集,则添加更改集,从而在此方法中检测到的更改占上风。

注意:您需要确保 UOW 已经拥有实体的 ChangeSet,否则它不会合并。

于 2014-04-29T13:31:59.257 回答
0

对于未来的读者,不惜一切代价尽量避开听众。这些很难测试,你的领域不应该依赖魔法。考虑 OP 的测试用例如何在没有 Doctrine 事件的情况下实现相同的目标:

工作班:

public function addTag(Tag $tag): void
{
    if (!$this->tags->contains($tag)) {
        $this->tags->add($tag);
        $tag->addWork($this);
    }
}

标记类:

public function addWork(Work $work): void
{
    if (!$this->works->contains($work)) {
        $work->addTag($this);
        $this->works->add($work);
        $this->worksCount = count($this->works);
    }
}

标记测试类:

public function testItUpdatesWorksCountWhenWorkIsAdded()
{
    $tag = new Tag();

    $tag->addWork(new Work());
    $tag->addWork(new Work());

    $this->assertSame(2, $tag->getWorkCount());
}

public function testItDoesNotUpdateWorksCountIfWorkIsAlreadyInCollection()
{
    $tag = new Tag();
    $work = new Work();
    $tag->addWork($work);

    $tag->addWork($work);

    $this->assertSame(1, $tag->getWorkCount());
}
于 2018-10-12T07:53:30.007 回答