Doctrine - 代理实体未正确更新

Doctrine - Proxy entity is not properly updated

场景

行为测试

事情是这样的:

  1. 我通过 Doctrine 存储库从数据库中获得了一个 Device 对象 - 该设备有一个 Attribute 集合尚未初始化(延迟加载)
  2. 因为我需要知道一个特定属性的 属性,这个特定属性从 Doctrine 加载并因此被初始化 - 它仍然是一个 Proxy__isInitialized__ 设置为 true
  3. 我向侦听器发送请求,要求更改此特定设备属性
  4. 监听器接收到请求并根据请求更改属性值(例如attribute->setValue(true)
  5. 侦听器发回确认更改的响应
  6. 现在测试通过 Attribute 实体存储库获取给定设备的属性,以检查它的值是否已从侦听器
  7. 在数据库中正确更改

问题出在第6点:属性值错误.

现在有人可能认为这是正常的,因为对象已经加载并在 Behat 测试中标记为已初始化,所以 Doctrine 不知道并发进程所做的更改,这很好。

然而,真正奇怪的是,Doctrine 无论如何都在第 6 点执行查询(使用 Doctrine SQL 日志检查)并且该查询返回的结果集包含该设备属性的不同值(即.不同value属性)但是属性变量不会自动更新!

事实上,为了更新它,我必须在属性上调用 $em->refresh() 或在第 6 点获取属性之前使用 $em->clear() 清除缓存。

这是 Doctrine 中的错误还是什么?有什么想法吗?

我想我找到了我要找的答案。

通过 Doctrine 类 进行调试(特别是在 UnitOfWork::createEntity() 中)我发现 Doctrine 不会覆盖现有实体数据,除非查询明确指定 Query::HINT_REFRESH 提示:

$result = $this->getEntityManager()->createQueryBuilder()
    ->select('e')
    ->from(MyEntity::class, 'e')
    ->getQuery()->setHint(Query::HINT_REFRESH, true)->getResult();

这样,即使实体已经加载到内存中,如果有新的数据库数据可用于该实体,Doctrine 将覆盖实体属性。此外,这不会像 $em->refresh() 那样触发新查询。

其实这也被official documentation证实了:

Query::HINT_REFRESH - This query is used internally by EntityManager::refresh() and can be used in userland as well. If you specify this hint and a query returns the data for an entity that is already managed by the UnitOfWork, the fields of the existing entity will be refreshed. In normal operation a result-set that loads data of an already existing entity is discarded in favor of the already existing entity.