【问题标题】:Unique error persisting entity updates to db with Doctrine使用 Doctrine 将实体更新持久化到数据库的唯一错误
【发布时间】:2022-10-24 19:43:21
【问题描述】:

我在我的 Symfony 项目中使用 Doctrine 来管理我的应用程序中的持久层。

最近,我在将更改从我的实体持久保存到我的数据库时遇到了一些问题。我遇到的问题是,当我更新实体并将其保存到我的数据库时,有时EntityManager 将我的实体视为一个新对象,因此它不执行更新操作,而是执行插入操作,从而导致我的数据库中的一个独特的异常错误。

As the docs say,更新对象时,您应该只执行以下步骤:

  • 从 Doctrine 中获取对象
  • 修改对象
  • (可选的)在实体管理器上调用persist()
  • 在实体管理器上调用flush()

注意我添加了(可选的)persist() 调用,因为正如文档所说,没有必要,因为 Doctrine 已经在监视对象的更改

现在事情已经解释了,这是我在代码中所做的工作:

$myEntity = $this->myEntityRepository->byId($id);

// make some changes to the entity
$myEntity->setSomething('something');

$this->myEntityRepository->save($entity);

我的存储库中的save() 操作如下:

$this->entityManager->persist($entity);
$this->entityManager->flush();

正如我所说,persist 操作应该只在持久化新实体时调用,但是由于 Doctrine 可以区分已经管理的实体和新实体,所以应该没问题。如果我没有调用 persist() 方法,而不是执行和插入操作并导致唯一的违规,它实际上什么都不做,因为它不会检测到我的操作的任何更改。
我总是使用persist() 方法的原因是因为我的存储库中的save() 操作用于新实体和对现有实体的更新。

正如我在another answer 中看到的那样,调用merge() 操作而不是persist() 应该可以解决问题,但我认为它不正确,因为我认为这只是一个“肮脏”的解决方案,加上方法@987654323 @ 在 Doctrine 的未来版本中。

那么,我在这里缺少什么?为什么在运行上述代码时有时会出现唯一错误?我的应用程序中只配置了一个连接和一个实体管理器。

我想补充一点,这个问题的唯一出现是在消费者(异步事件)中执行的代码中,而不是在 API 本身中,但是每当我收到一个新事件时,都会创建一个新的数据库连接到确保我在之前的某个事件中使用的实体管理器没有重叠问题。

我的猜测是,在我从存储库中获取实体的那一行(即我使用find() 方法)和我将它保存到数据库中的那一行(即我使用flush() 方法)之间,实体管理器不知何故从其 UnitOfWork 中删除实体,因此它将其视为新实体而不是托管实体。

【问题讨论】:

  • 您能否详细说明“异步事件”?您是否以某种方式坚持排队,或类似的方式?
  • @ChrisHaas 事件被发布到 RabbitMQ 队列,然后从该队列中读取并在单独的 PHP 进程中处理

标签: php symfony doctrine-orm doctrine


【解决方案1】:

我最近在一些代码中发现的一个问题是传递实体的位置——通过 RabbitMq 消息和从头创建的实体,包括 id——$x = new Entity(); $x->setId($data['id');$x->setName($data['name'); # ... etc)。

但是,设置 id 并不会使实体由 Doctrine “管理” - 仅读取原始记录(来自数据库)和然后更新它。如上所述保持 $x 将创建一个新记录 - 并忽略设置的 id。

我会确保(也许在记录中有一些断言你正在获取必须通过 - 或因错误而死,至少目前如此)以便知道你总是在处理一个已知实体(我也假设你的->byId($id) 调用只是内部的 ->find($id))。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    相关资源
    最近更新 更多