php - Doctrine - 代理实体未正确更新
问题描述
设想
- 我有一个与实体
Device
有双向OneToMany关系的Attribute
实体 - 我有一个 CLI 进程,它侦听传入的请求并最终执行一些发送回响应的操作
- 我有一个 Behat 测试,它检查设备属性是否已正确更改,向所述侦听器发送请求
行为测试
这就是发生的事情:
- 我
Device
通过 Doctrine 存储库从 DB 获取一个对象 - 该设备有一个Attribute
尚未初始化的集合(延迟加载) - 由于我需要知道特定属性的属性,因此该特定属性从 Doctrine 加载并因此被初始化 - 它仍然是 a
Proxy
但已__isInitialized__
设置为true
- 我向侦听器发送请求,要求更改此特定设备属性
- 侦听器接收请求并根据请求更改属性值(例如
attribute->setValue(true)
) - 侦听器发回响应以确认更改
- 现在测试通过
Attribute
实体存储库获取给定设备的属性,以检查其值是否已从侦听器在 DB 中正确更改
问题出现在第 6 点:属性的值是错误的。
现在有人可能认为这是正常的,因为对象已经加载并在 Behat 测试中标记为已初始化,因此 Doctrine 不知道并发进程所做的更改,这很好。
然而真正奇怪的是,Doctrine 无论如何都在第 6 点执行查询(使用 Doctrine SQL 日志记录检查),并且该查询返回的结果集包含该设备属性的不同值(即不同value
的属性)但属性变量不会自动更新!
事实上,为了更新它,我必须在第 6 点获取属性之前调用$em->refresh()
属性或清除缓存。$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()
。
事实上,官方文档也证实了这一点:
Query::HINT_REFRESH - 此查询由 EntityManager::refresh() 内部使用,也可以在用户空间中使用。如果您指定此提示并且查询返回已由 UnitOfWork 管理的实体的数据,则将刷新现有实体的字段。在正常操作中,加载已存在实体的数据的结果集将被丢弃,以支持已存在的实体。
推荐阅读
- linux-mint - 如果面板变得不可见,如何重置/重新启动 Cinnamon
- javascript - 使用 React 类创建多个按钮
- c - “20”[1] 有什么作用?
- html - tds 中圆圈之间的车道
- c# - 如何在 dot net core 3.0/3.1 的剃须刀页面中添加区域?
- haskell - 重写函数haskell
- azure-devops - 构建管道在“初始化作业”步骤失败
- docker - Docker info 显示容器,但 docker container ls 不显示
- python - 如果某些键具有所需的值,如何遍历字典列表并打印字典
- c# - 打印时的 C# 字符变成数字