我被卡住了:-)
也许我只是在研究中使用了错误的关键词。但我没打通。所以我希望有一个人能帮助我!
我有一个单向的ManyToMany协会。当我试图提交表单(因此坚持)时,我得到了错误:
通过关系"TrainerInInInPool\AppBundle\entity\Trainer#applicationFields"找到了一个新实体,该实体未配置为级联实体的持久化操作:TrainerIninPool\AppBundle\entity\ApplicationField@0000000022ef36c600000000087bcbc3.
当我进行"级联持久化"时,会创建一个实际上已经存在的新实体。
我有两个实体:
- 培训师
- 应用程序字段
培训师与ApplicationField有一个单向的ManyToMany关联:
class Trainer {
public function __construct()
{
$this->applicationFields = new ArrayCollection();
}
[...]
/**
* @ORMManyToMany(targetEntity="ApplicationField")
*/
protected $applicationFields;
ApplicationField有一个自引用的OneToMany关联:
class ApplicationField {
public function __construct() {
$this->children = new ArrayCollection();
}
[...]
/**
* @ORMOneToMany(targetEntity="ApplicationField", mappedBy="parent")
*/
private $children;
/**
* @ORMManyToOne(targetEntity="ApplicationField", inversedBy="children")
* @ORMJoinColumn(name="parent_id", referencedColumnName="id")
*/
private $parent;
我想创建一个表单,在其中我可以添加一个Trainer-ApplicationField关联。
因此,我有一个ApplicationFieldCollectionType:
class ApplicationFieldCollectionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('applicationFields', 'collection', array(
'type' => new ApplicationFieldType(),
'allow_add' => true,
'label' => false
))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'TrainerInnenPoolAppBundleEntityTrainer',
));
}
嵌入类型如下:
class ApplicationFieldType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('applicationFieldName', 'entity', array(
'class' => 'TrainerInnenPoolAppBundle:ApplicationField',
'label' => false,
'mapped' => false,
'property' => 'name',
'query_builder' => function(EntityRepository $repository) {
return $repository->createQueryBuilder('application_field')
->where('application_field.parent is NULL');
}
));
$builder->add('name', 'entity', array(
'class' => 'TrainerInnenPoolAppBundle:ApplicationField',
'label' => false,
'property' => 'name',
'query_builder' => function(EntityRepository $repository) {
return $repository->createQueryBuilder('application_field')
->where('application_field.parent = 1');
}
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'TrainerInnenPoolAppBundleEntityApplicationField',
));
}
最后缺失的部分:控制器:
public function editApplicationField($id, Request $request)
{
$entityManager = $this->getDoctrine()->getEntityManager();
$trainer = $entityManager->getRepository('TrainerInnenPoolAppBundle:Trainer')->find($id);
$editForm = $this->createForm(new ApplicationFieldCollectionType(), $trainer);
if ($request->getMethod() == 'POST') {
$editForm->handleRequest($request);
$entityManager->flush();
}
当我从Trainer获取ApplicationField实体并尝试持久化这些实体时,
$editForm->handleRequest($request);
$af = $trainer->getApplicationFields();
foreach ($af as $applicationField) {
$trainer->addApplicationField($applicationField);
$entityManager->persist($applicationField);
}
$entityManager->flush();
我不能这样做,因为我得到了一个"密钥PRIMARY的重复条目"-异常。
我想我没有抓住任何明显的要点。如果有人能帮助我,给我一个提示,或者只是提到用信息更新我的问题,我会非常感激。
亲切问候。。。
您的嵌套类型setter由于缺少属性而未被调用:
->add('applicationFields', 'collection', array(
'type' => new ApplicationFieldType(),
...
'by_reference' => false
...
http://symfony.com/doc/current/reference/forms/types/collection.html#by-参考
当您计划具有可添加/可删除的集合字段("allow_add"、"allow_delete")时,应始终提供"by_reference"=>false选项,以便直接在相关实体上调用setter,然后建立关联,而不是从原始实体中建立链方法。
希望这能有所帮助!
您需要cascade={"persistent"}注释,因为您希望将整个实体及其与ApplicationField的关联持久化。如果不使用cascade={"persistent"},则必须手动持久化实体。
实体已经添加到训练器中,所以如果你想手动持久化实体,你应该删除行
$trainer->addApplicationField($applicationField);
并且仅执行持久化。
这应该行得通。试试吧。但我认为效果会和你使用级联持久化的效果一样。所以我认为这不是最终的解决方案,而是理解问题的第一步,为什么手册以前不起作用。