首页 > 解决方案 > Doctrine - 代理实体未正确更新

问题描述

设想

行为测试

这就是发生的事情:

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

问题出现在第 6 点:属性的值是错误的

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

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

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

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

标签: phpsymfonydoctrine-ormbehat

解决方案


我想我找到了我正在寻找的答案。

通过 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()

事实上,官方文档也证实了这一点:

Query::HINT_REFRESH - 此查询由 EntityManager::refresh() 内部使用,也可以在用户空间中使用。如果您指定此提示并且查询返回已由 UnitOfWork 管理的实体的数据,则将刷新现有实体的字段。在正常操作中,加载已存在实体的数据的结果集将被丢弃,以支持已存在的实体。


推荐阅读