【问题标题】:Doctrine - Proxy entity is not properly updatedDoctrine - 代理实体未正确更新
【发布时间】:2018-07-20 20:39:35
【问题描述】:

场景

  • 我有一个实体 Device,它与 Attribute 实体具有双向 OneToMany 关系
  • 我有一个 CLI 进程,它侦听传入的请求并最终执行一些操作以发回响应
  • 我有一个 Behat 测试,它检查设备属性是否已正确更改,向所述侦听器发送请求

行为测试

会发生这样的事情:

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

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

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

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

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

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

【问题讨论】:

    标签: php symfony doctrine-orm behat


    【解决方案1】:

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

    通过 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 - 此查询由内部使用 EntityManager::refresh() 也可以在用户空间中使用。如果你 指定此提示,查询将返回实体的数据,该实体是 已由 UnitOfWork 管理,现有实体的字段 将被刷新。在正常操作中,加载数据的结果集 已经存在的实体被丢弃以支持已经存在的实体 现有实体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多