考虑以下架构:
[Work]
id
tags ManyToMany(targetEntity="Tag", inversedBy="works", cascade={"persist"})
[Tag]
id
works_count
works ManyToMany(targetEntity="Work", mappedBy="tags")
works_count
是Tag::works
的计数器缓存。
我在工作上有一个onFlush
监听器,用于检查Work::tags
是否已更改,并更新每个标记“works_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
,为什么在这种情况下它不起作用?
P.S
标签由EntityManager管理($em->contains($tag)
返回true)
答案 0 :(得分:3)
此问题与UnitOfWork中的错误有关,最后在2014年9月11日发布Doctrine ORM 2.4.3时已修复。有关详细信息,请参阅DDC-2996。
答案 1 :(得分:2)
似乎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);
}
答案 2 :(得分:1)
在doctrine 2.4.1中,仅当您在事件侦听器中更改标记并且UOW包含标记ChangeSet(在事件侦听器之外发生的更改)时,才使用recomputeSingleEntityChangeSet。基本上,recomputeSingleEntityChangeSet是一个合并实体的ChangeSet的函数。
来自该功能的Doc 传递的实体必须是管理实体。如果实体已经有一个更改集,因为在提交周期中调用了此方法,则会添加更改集,以此方法中检测到的更改为准。
注意:您需要确保UOW已经有实体的ChangeSet,否则它将不会合并。
答案 3 :(得分:0)
对于将来的读者,不惜一切代价,请尝试避免 听众。这些几乎无法测试,您的领域不应该依赖魔术。考虑OP的测试用例如何在没有教义事件的情况下实现相同的目标:
工作课程:
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);
}
}
TagTest 类:
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());
}