学说持久化实体在 entityManager->persist 和 unitOfWork->persist 之间更改

Posted

技术标签:

【中文标题】学说持久化实体在 entityManager->persist 和 unitOfWork->persist 之间更改【英文标题】:doctrine persisted entity changed between entityManager->persist and unitOfWork->persist 【发布时间】:2015-04-12 20:43:41 【问题描述】:

在我的 symfony2/doctrine2 应用程序中,我有一个奇怪的情况,当持久化一个修改的实体时,更改没有刷新到数据库,我不明白为什么。

下面是我的代码:

$date = $subscription->getPaymentValidUntil()->format('d/m/Y');
$period = $payment->getDetail('period');
$validDate = $subscription->getPaymentValidUntil()
    ->add(new\DateInterval($period == Subscription::MONTH ? 'P1M' : 'P1Y'))
;

$subscription->setPaymentValidUntil($validDate);
$this->em->persist($subscription);

exit(var_dump(array(
    $date,
    $this->em->getUnitOfWork()->getScheduledEntityUpdates(),
    $subscription->getPaymentValidUntil(),
)));

$this->em->flush();

vardump 的输出如下:

array (size=3)
  0 => string '12/05/2015' (length=10)
  1 => 
    array (size=0)
      empty
  2 => 
    object(DateTime)[2295]
      public 'date' => string '2015-06-12 18:52:37' (length=19)
      public 'timezone_type' => int 3
      public 'timezone' => string 'Europe/Paris' (length=12)

如果我在 vardump 之前刷新或删除 vardump,确实,我的数据库中的日期值不会改变。为什么?

如您所见,我在此日期值上添加了一个月,它反映在实体中,但未计划更新。我该如何解决这个问题?

编辑:我已经深入研究了实体管理器持久化功能,我发现在 Doctrine\ORM\EntityManager::persist 中转储实体时,日期很好,但是在 Doctrine\ORM\UnitOfWork 中转储它时::persist,日期不知何故被重置为原来的日期:

Doctrine\ORM\EntityManager::persist:转储更新的实体

public function persist($entity)

    if ( ! is_object($entity)) 
        throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()' , $entity);
    

    $this->errorIfClosed();

    if ($entity instanceof Subscription) exit(var_dump($entity));

    $this->unitOfWork->persist($entity);

Doctrine\ORM\UnitOfWork::persist :转储未修改的实体:为什么?

private function doPersist($entity, array &$visited)

    if ($entity instanceof Subscription) exit(var_dump($entity));

        $oid = spl_object_hash($entity);

        if (isset($visited[$oid])) 
            return; // Prevent infinite recursion
        

【问题讨论】:

你的$subscription->getPaymentValidUntil() 是什么? 它正在返回我正在修改的日期时间。我加了一个月。从我的转储中可以看出,修改前设置为 12/05,修改后设置为 12/06,但没有任何更新的计划。 为什么在你需要getScheduledEntityUpdates的时候获取getScheduledEntityInsertions 是的,对不起,更新也一样,我尽力了,它也是空的。我会纠正这个 发布您的实体代码和映射信息(如果不在注释中)。 【参考方案1】:

DateTime 毕竟是对象,并且总是通过引用传递。所以,我强烈建议你像这样编辑你的代码:

$period = $payment->getDetail('period');
$validDate = clone $subscription->getPaymentValidUntil();
$validDate->add(new \DateInterval($period == Subscription::MONTH ? 'P1M' : 'P1Y'));
$subscription->setPaymentValidUntil($validDate);
$this->em->persist($subscription);
$this->em->flush();

这样,您可以确保将不同的对象传递给实体,并避免 EntityManager 中的任何细微错误。

【讨论】:

arf,最后,这完全是关于克隆对象。谢谢!

以上是关于学说持久化实体在 entityManager->persist 和 unitOfWork->persist 之间更改的主要内容,如果未能解决你的问题,请参考以下文章

持久化实体而不将其附加到 EntityManager

EntityManager方法简介

学说 2 和 ORM:如何缓存某个实体的每个查询?

错误持久化实体列表 - java.lang.IllegalStateException:不允许在共享EntityManager上创建事务

Spring Boot-------JPA——EntityManager构建通用DAO

学说刷新不更新相关的集合实体