【问题标题】:Changes on ArrayCollection's items are done, but not persisted in databaseArrayCollection 项目的更改已完成,但未保存在数据库中
【发布时间】:2018-07-20 19:23:49
【问题描述】:

简介

所以,我有一个实体 Presence 被 Doctrine 监视。
我还有另一个实体 Decision 不受 Doctrine 关注。

Presence实体有一个属性$decisions,类型为ArrayCollection,包含0到n个Decision实体。

由于我不存储 ArrayCollection 中包含的每个 Decision 对象,我将属性 $decision 键入为 Doctrine Array,到目前为止一切正常。

我可以从数据库中取回整个 Presence 对象,它包含我添加到其中的每个 Decision 对象。

问题

当我编辑 Presence 对象的 ArrayCollection 中存在的一个 Decision 对象时,例如:

    foreach($Presence->getDecisions() as $decision) {
        $decision->setMorning($value);
    }

修改是在本地应用的,我可以在做dump($Presence);时看到它们

Presence {#2354 ▼
  #id: 8
  #decisions: ArrayCollection {#1409 ▼
    -elements: array:6 [▼
      0 => Decision {#1408 ▼
        #token_id: "005867b2915438c03383bb831d87c26346c586d6ecd46b735c7a23b4fabb682a8ac34a90ea3d53cc55c2209deaa83337abeb2b98ded43967fcfb0f4d04d5ada6"
        #date: DateTime @1531692000 {#1407 ▶}
        #morning: -1
        #afternoon: 0
      }
      1 => Decision {#1406 ▶}
      2 => Decision {#1404 ▶}
      3 => Decision {#1402 ▶}
      4 => Decision {#1400 ▶}
      5 => Decision {#1398 ▶}
    ]
  }
  #last_edit_date: DateTime @1532109183 {#2454 ▼
    date: 2018-07-20 19:53:03.062940 Europe/Berlin (+02:00)
  }
  #user: User {#1393 ▶}
}

在这个dump() 上,你可以看到属性#morning: -1 是setter 调用的结果。

但是当我尝试用$this->entityManager->flush(); 刷新更改时,ArrayCollection 没有被修改。

起初我认为这是更改检测的问题,所以我在我的 Presence 实体中添加了一个#last_edit_date DateTime 字段。
有趣的是,这个属性在刷新时更新得很好。

ArrayCollection 似乎由于某种原因不会更新。

更新

为了完成我的帖子,这里有更多信息:

控制器中的完整方法

/**
* @Route(name="edit_decision", path="/edit-decision/{tokenDate}/{dayPart}/{newValue}")
*/
public function EditDecisionAction(Request $request)
{
    $token = $request->get('tokenDate');
    $dayPart = $request->get('dayPart');
    $newValue = intval($request->get('newValue'));

    $myPresence = $this->em->getRepository('AppBundle:Presence')->findOneBy([
        'user' => $this->connectedUser
    ]);

    /** @var ArrayCollection $decisionCollection */
    $decisionCollection = $myPresence->getDecisions();

    $found = FALSE;
    
    /** @var Decision $decision */
    foreach ($decisionCollection as $decision) {
        if ($decision->getTokenId() == $token) {
            
            $found = TRUE;

            if ($dayPart === 'morning') {
                $decision->setMorning($newValue);
            }elseif ($dayPart === 'afternoon') {
                $decision->setAfternoon($newValue);
            }
            break;
        }
    }
    
    if (!$found) {
        throw $this->createNotFoundException();
    }
    
    // I set a new Date to trigger a modification on the Presence Entity : It works
    $myPresence->setLastEditDate(new \DateTime());
    
    // Here is the dump that you can see above
    dump($myPresence);
    
    $this->em->flush();
    
    try{
        $this->em->flush();
        return $this->json([
            'status' => TRUE
        ]);
    }catch (\Exception $exception) {
        return $this->json([
            'status' => FALSE
        ]);
    }
}

包含 ArrayCollection 的属性:

/**
 * Doctrine Type Array
 *
 * @ORM\Column(type="array", nullable=true)
 */
 protected $decisions;

欢迎任何帮助甚至提示! 谢谢:)

更新 2

感谢这篇文章,我可能已经找到了解决方案:
How to force Doctrine to update array type fields?

问题来自我存储对象的原则数组类型:

Doctrine 使用相同的运算符 (===) 来比较新旧值之间的变化。在具有不同数据的同一对象(或对象数组)上使用的运算符始终返回 true。还有另一种方法可以解决这个问题,你可以克隆一个需要更改的对象。

更新 3

Nope 仍然不会保留对数据库中 ArrayCollection 的项目所做的更改。 将尝试克隆:添加:删除旧的,我们将看看会发生什么。

【问题讨论】:

标签: php symfony doctrine-orm symfony-3.4


【解决方案1】:

最终更新

好的,所以我终于用一个技巧让它工作了。

主要问题是 Doctrine 对 Array 类型的更改检测的行为。

如上所述,学说确实: Array === Array 以检查是否需要进行更改。 有点奇怪,因为当您从 ArrayCollection 中添加或删除一个元素时,对于 Doctrine,该集合仍然等同于先例状态。 应该有一种方法可以测试 2 个对象之间的等价性,例如 Java 中的 .equals 以消除这些歧义。

无论如何我做了什么来解决它:
我将收藏存储到初始状态:

$decisionCollection = $myPresence->getDecisions();

我放置我的设置器并相应地修改我的收藏:

foreach ($myPresence->getDecisions() as $key => $decision) {
    if ($decision->getTokenId() == $token) {
                
        if ($dayPart === 'morning') {
            $decision->setMorning($newValue);
        } elseif ($dayPart === 'afternoon') {
            $decision->setAfternoon($newValue);
        }
                
        break;
    }
}

然后是诀窍:

$myPresence->unsetDecisions();
$this->em->flush();

我完全取消了我的收藏($this->collection = NULL)并第一次刷新。
它触发更新,因为 Array !== NULL
然后我用包含设置对象的更新集合设置我的集合:

$myPresence->setDecisions($decisionCollection);
$myPresence->setLastEditDate(new \DateTime());

最后一次刷新以保留新的更改。

感谢大家的时间和您的 cmets!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-22
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    相关资源
    最近更新 更多