ArrayCollection 项目的更改已完成,但未保存在数据库中
Changes on ArrayCollection's items are done, but not persisted in database
简介
所以,我有一个实体 Presence 被 Doctrine 监视着。
我还有另一个实体 Decision 没有被 Doctrine 关注。
Presence 实体具有属性 $decisions,类型为 ArrayCollection,包含 0 到 n Decision 个实体。
因为我没有存储包含在 ArrayCollection 中的每个 Decision 对象,所以我输入属性 $decision 作为 Doctrine Array到目前为止一切正常。
我可以从数据库中获取整个 Presence 对象,它包含我添加到其中的每个 Decision 对象。
问题
当我编辑 Decision 对象时,它存在于我的 Presence 对象的 ArrayCollection 中,例如:
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 似乎由于某种原因不会更新。
更新
为了完成我的 post 这里有更多信息:
控制器中的完整方法
/**
* @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
多亏了这个 post :
How to force Doctrine to update array type fields?
我可能找到了解决方案
问题出在我存储对象的数组类型上:
Doctrine uses identical operator (===) to compare changes between old and new values. The operator used on the same object (or array of objects) with different data always return true. There is the other way to solve this issue, you can clone an object that needs to be changed.
更新 3
Nope 仍然不会保留对数据库中 ArrayCollection 的项目所做的更改。
尝试克隆:添加:删除旧的,我们将看到会发生什么。
最终更新
好的,所以我终于使用了一个技巧让它工作。
主要问题是 Doctrine 的行为改变了对 Array 类型的检测。
正如上面引用的,doctrine 做的是:Array === Array 来检查是否有要进行的更改。
有点奇怪,因为当您从 ArrayCollection 添加或删除元素时,对于 Doctrine,collection 仍然等同于先例状态。
应该有一种方法来测试 2 objects 之间的等价性,例如 Java .equals 以消除这些歧义。
无论如何我做了什么来解决它:
我将 collection 存储到初始状态:
$decisionCollection = $myPresence->getDecisions();
我放置我的二传手并相应地修改我的 collection :
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();
我完全取消了我的 collection ($this->collection = NULL) 并第一次刷新。
它触发更新,因为 Array !== NULL
然后我将我的 collection 设置为更新后的 objects :
$myPresence->setDecisions($decisionCollection);
$myPresence->setLastEditDate(new \DateTime());
并最后一次刷新以保留新的更改。
感谢大家的宝贵时间和意见!
简介
所以,我有一个实体 Presence 被 Doctrine 监视着。
我还有另一个实体 Decision 没有被 Doctrine 关注。
Presence 实体具有属性 $decisions,类型为 ArrayCollection,包含 0 到 n Decision 个实体。
因为我没有存储包含在 ArrayCollection 中的每个 Decision 对象,所以我输入属性 $decision 作为 Doctrine Array到目前为止一切正常。
我可以从数据库中获取整个 Presence 对象,它包含我添加到其中的每个 Decision 对象。
问题
当我编辑 Decision 对象时,它存在于我的 Presence 对象的 ArrayCollection 中,例如:
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 似乎由于某种原因不会更新。
更新
为了完成我的 post 这里有更多信息:
控制器中的完整方法
/**
* @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
多亏了这个 post :
How to force Doctrine to update array type fields?
问题出在我存储对象的数组类型上:
Doctrine uses identical operator (===) to compare changes between old and new values. The operator used on the same object (or array of objects) with different data always return true. There is the other way to solve this issue, you can clone an object that needs to be changed.
更新 3
Nope 仍然不会保留对数据库中 ArrayCollection 的项目所做的更改。 尝试克隆:添加:删除旧的,我们将看到会发生什么。
最终更新
好的,所以我终于使用了一个技巧让它工作。
主要问题是 Doctrine 的行为改变了对 Array 类型的检测。
正如上面引用的,doctrine 做的是:Array === Array 来检查是否有要进行的更改。 有点奇怪,因为当您从 ArrayCollection 添加或删除元素时,对于 Doctrine,collection 仍然等同于先例状态。 应该有一种方法来测试 2 objects 之间的等价性,例如 Java .equals 以消除这些歧义。
无论如何我做了什么来解决它:
我将 collection 存储到初始状态:
$decisionCollection = $myPresence->getDecisions();
我放置我的二传手并相应地修改我的 collection :
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();
我完全取消了我的 collection ($this->collection = NULL) 并第一次刷新。
它触发更新,因为 Array !== NULL
然后我将我的 collection 设置为更新后的 objects :
$myPresence->setDecisions($decisionCollection);
$myPresence->setLastEditDate(new \DateTime());
并最后一次刷新以保留新的更改。
感谢大家的宝贵时间和意见!