Symfony - 多对一关系的外部 属性 的未定义索引
Symfony - Undefined index of foreign property of a manyToOne relation
这个案子有点复杂。我有一个 Controller 操作 editCreateFirstFormPart
,它处理 Workflow
对象的某些字段并呈现两部分表单的适当第一部分。
如果我使用存储对象的 ID 调用此操作方法的路由,则表单将按应有的方式加载所有字段。我将填充表格的数据库对象存储在当前会话中,以防用户决定取消第二种形式的编辑:
// Persist all changes of made in the first form part
$manager->persist($workflow);
$manager->flush();
// In case the wolkflow already exists store it in the session
if(!$newWorkflow) $this->get('session')->set($workflowSessionName, $workflowBeforeSubmit);
return $this->redirectToRoute('pec_test_pra_edit_workflow_second_part', array(
'project' => $project->getId(),
'workflow' => $workflow->getId(),
'newWorkflow' => $newWorkflow,
// Pass the name in the session of the stored workflow to the action method which handles the second form
'workflowSessionName' => $workflowSessionName,
));
这很有魅力。现在,如果(我检索到)用户通过 cancel
按钮提交第二个表单,我想将存储在数据库中的对象重置为第一个表单部分提交之前的状态。因此我获取存储在会话中的对象并想要 persist
它:
if($sessionObject instanceof Workflow) {
$manager = $this->getObjectManager();
$sessionObject = $session->get($workflowSessionName);
$manager->persist($sessionObject);
$manager->flush();
}
这里出现以下错误:
Notice: Undefined index: 0000000061675b3d0000000022ddb0a6 in vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php (line 2917)
Line 2917: return $this->entityIdentifiers[spl_object_hash($entity)];
UnitOfWork->getEntityIdentifier(object(Fuel))// gets called after prepareUpdateData
BasicEntityPersister->prepareUpdateData(object(MProject))
我的实体 Workflow
与 Project
class 具有单向 manyToOne 关系。 MProject
class 扩展了 Project
并且有一个 fuel
属性 of class Fuel
.
所以 一个 Fuel
有很多 MProject
s (oneToMany) 和 Many MProject
有一个 Fuel
(manyToOne)。以下是 .orm.yml
文件的相应部分:
Fuel.orm.yml
:
'ABundle\Entity\Fuel':
...
oneToMany:
projects:
targetEntity: 'ABundle\Entity\MProject'
mappedBy: fuel
里面 Fuel
class:
class Fuel {
/**
* The collection of projects using the fuel.
*
* @var \Doctrine\Common\Collections\Collection
*/
private $projects;
...
}
MProject.orm.yml
:
'ABundle\Entity\MProject':
repositoryClass: 'ABundle\Repository\MProjectRepository'
type: entity
manyToOne:
fuel:
targetEntity: 'ABundle\Entity\Fuel'
inversedBy: projects
里面 MProject
class:
use BBundle\Entity\Project as BaseProject; // Origin of Project in my Entity
class MProject extends BaseProject implements SearchableTypeAlias {
/**
* The fuel used by the project.
*
* @var Fuel
*/
protected $fuel;
...
}
Workflow.orm.yml
:
MyBundle\Entity\Workflow:
...
manyToOne:
project:
targetEntity: BBundle\Entity\Project
cascade: [persist]
...
里面 Workflow
class:
use BBundle\Entity\Project;
class Workflow {
/**
* @var Project
*/
private $project;
...
}
我真的不知道我的用例出了什么问题,特别是因为在第一个控制器操作方法中调用 persist
存储 $workflow
对象没有问题。
如何解决这个 未定义索引 错误?
由于您正在使用重定向路由,因此正在创建一个新请求以加载表单的第二部分。此时 identityMap 已重建,并且没有引用先前加载的会话对象(工作流)的映射(长 id)。尝试再次从数据库中检索对象并使用会话对象的值设置属性。
PS:可能有一种我不知道的更简洁的方法。
您的问题是您正在尝试从 EntityManager
中保存实体 detached。 Workflow
、Project
实体被标记为 NEW
并安排插入而不是更新。在探索会话的 Project
的 project->fuel
关联期间,找到另一个具有非空 id
值的 Fuel
实体。但是它是分离的并且在 EntityManager
中找不到 id
因此引发了异常。
应该在数据库中有相应行但不是由 EntityManager
加载的实体(在您的示例中从会话中反序列化)应该 merged 到 EntityManager
。您应该合并所有 Workflow
、Project
、Fuel
实例。最简单的方法是为级联合并 cascade: [merge]
配置 workflow->project
和 project->fuel
关联,并仅合并会话 Workflow
.
$manager = $this->getObjectManager();
$sessionObject = $session->get($workflowSessionName);
$manager->merge($sessionObject);
$manager->flush();
请注意,这会自动将实体字段值替换为从会话中获取的值。
这个案子有点复杂。我有一个 Controller 操作 editCreateFirstFormPart
,它处理 Workflow
对象的某些字段并呈现两部分表单的适当第一部分。
如果我使用存储对象的 ID 调用此操作方法的路由,则表单将按应有的方式加载所有字段。我将填充表格的数据库对象存储在当前会话中,以防用户决定取消第二种形式的编辑:
// Persist all changes of made in the first form part
$manager->persist($workflow);
$manager->flush();
// In case the wolkflow already exists store it in the session
if(!$newWorkflow) $this->get('session')->set($workflowSessionName, $workflowBeforeSubmit);
return $this->redirectToRoute('pec_test_pra_edit_workflow_second_part', array(
'project' => $project->getId(),
'workflow' => $workflow->getId(),
'newWorkflow' => $newWorkflow,
// Pass the name in the session of the stored workflow to the action method which handles the second form
'workflowSessionName' => $workflowSessionName,
));
这很有魅力。现在,如果(我检索到)用户通过 cancel
按钮提交第二个表单,我想将存储在数据库中的对象重置为第一个表单部分提交之前的状态。因此我获取存储在会话中的对象并想要 persist
它:
if($sessionObject instanceof Workflow) {
$manager = $this->getObjectManager();
$sessionObject = $session->get($workflowSessionName);
$manager->persist($sessionObject);
$manager->flush();
}
这里出现以下错误:
Notice: Undefined index: 0000000061675b3d0000000022ddb0a6 in vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php (line 2917)
Line 2917:return $this->entityIdentifiers[spl_object_hash($entity)];
UnitOfWork->getEntityIdentifier(object(Fuel))// gets called after prepareUpdateData
BasicEntityPersister->prepareUpdateData(object(MProject))
我的实体 Workflow
与 Project
class 具有单向 manyToOne 关系。 MProject
class 扩展了 Project
并且有一个 fuel
属性 of class Fuel
.
所以 一个 Fuel
有很多 MProject
s (oneToMany) 和 Many MProject
有一个 Fuel
(manyToOne)。以下是 .orm.yml
文件的相应部分:
Fuel.orm.yml
:
'ABundle\Entity\Fuel':
...
oneToMany:
projects:
targetEntity: 'ABundle\Entity\MProject'
mappedBy: fuel
里面 Fuel
class:
class Fuel {
/**
* The collection of projects using the fuel.
*
* @var \Doctrine\Common\Collections\Collection
*/
private $projects;
...
}
MProject.orm.yml
:
'ABundle\Entity\MProject':
repositoryClass: 'ABundle\Repository\MProjectRepository'
type: entity
manyToOne:
fuel:
targetEntity: 'ABundle\Entity\Fuel'
inversedBy: projects
里面 MProject
class:
use BBundle\Entity\Project as BaseProject; // Origin of Project in my Entity
class MProject extends BaseProject implements SearchableTypeAlias {
/**
* The fuel used by the project.
*
* @var Fuel
*/
protected $fuel;
...
}
Workflow.orm.yml
:
MyBundle\Entity\Workflow:
...
manyToOne:
project:
targetEntity: BBundle\Entity\Project
cascade: [persist]
...
里面 Workflow
class:
use BBundle\Entity\Project;
class Workflow {
/**
* @var Project
*/
private $project;
...
}
我真的不知道我的用例出了什么问题,特别是因为在第一个控制器操作方法中调用 persist
存储 $workflow
对象没有问题。
如何解决这个 未定义索引 错误?
由于您正在使用重定向路由,因此正在创建一个新请求以加载表单的第二部分。此时 identityMap 已重建,并且没有引用先前加载的会话对象(工作流)的映射(长 id)。尝试再次从数据库中检索对象并使用会话对象的值设置属性。
PS:可能有一种我不知道的更简洁的方法。
您的问题是您正在尝试从 EntityManager
中保存实体 detached。 Workflow
、Project
实体被标记为 NEW
并安排插入而不是更新。在探索会话的 Project
的 project->fuel
关联期间,找到另一个具有非空 id
值的 Fuel
实体。但是它是分离的并且在 EntityManager
中找不到 id
因此引发了异常。
应该在数据库中有相应行但不是由 EntityManager
加载的实体(在您的示例中从会话中反序列化)应该 merged 到 EntityManager
。您应该合并所有 Workflow
、Project
、Fuel
实例。最简单的方法是为级联合并 cascade: [merge]
配置 workflow->project
和 project->fuel
关联,并仅合并会话 Workflow
.
$manager = $this->getObjectManager();
$sessionObject = $session->get($workflowSessionName);
$manager->merge($sessionObject);
$manager->flush();
请注意,这会自动将实体字段值替换为从会话中获取的值。