Forms Symfony2表单和Doctrine2-更新指定实体中的外键失败

Forms Symfony2表单和Doctrine2-更新指定实体中的外键失败,forms,symfony,doctrine-orm,symfony-forms,Forms,Symfony,Doctrine Orm,Symfony Forms,我有个人资料和研究。一个人可以完成许多研究。表单呈现正确。有一个按钮“AddNewStudy”,我使用jQuery在数据原型的基础上添加了另一个子表单,效果很好。当我提交带有新子表单的表单时,会出现数据库错误 Integrity constraint violation: 1048 Column 'profile_id' cannot be null 我理解这个错误,但我不知道如何摆脱它。我知道我可以在控制器中绑定后更新研究集合,但我希望有一种方法可以在注释中正确配置它。当我只更新实体时,一

我有个人资料和研究。一个人可以完成许多研究。表单呈现正确。有一个按钮“AddNewStudy”,我使用jQuery在数据原型的基础上添加了另一个子表单,效果很好。当我提交带有新子表单的表单时,会出现数据库错误

Integrity constraint violation: 1048 Column 'profile_id' cannot be null 
我理解这个错误,但我不知道如何摆脱它。我知道我可以在控制器中绑定后更新研究集合,但我希望有一种方法可以在注释中正确配置它。当我只更新实体时,一切正常

代码是:

class Profile {
    /**
     * @var integer $profileId
     *
     * @ORM\Column(name="profile_id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $profileId;
...
    /**
     *
     * @var Study
     * @ORM\OneToMany(targetEntity="Study", mappedBy="profile", cascade={"persist", "remove"})
     */
    private $study;

    public function __construct()
    {
        $this->study = new \Doctrine\Common\Collections\ArrayCollection();
    }
...
}

用s(g)字母。底层数据库结构是

CREATE TABLE IF NOT EXISTS `profile` (
  `profile_id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`profile_id`),
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `study` (
  `study_id` int(11) NOT NULL AUTO_INCREMENT,
  `profile_id` int(11) NOT NULL,
  PRIMARY KEY (`study_id`),
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

ALTER TABLE `study`
  ADD CONSTRAINT `study_fk2` FOREIGN KEY (`profile_id`) REFERENCES `profile` (`profile_id`);
表单构建者是:

class ProfileType extends AbstractType {

    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('study', 'collection', array(
                    'type' => new StudyType(),
                    'allow_add' => true,
                    'allow_delete' => true
                        )
                )
    }
...
}

Javascript部分

function profileNewStudy() {
    var nr = $('[class^=profile_study_][class*=type2]').last().parent();
    nr = nr.attr('id').split('_');
    nr = nr.pop()*1 + 1;
    var proto = $('#profile_study').data('prototype');
    proto = proto.replace(/\$\$name\$\$/g, nr);
    $('#profile_study').append(proto).find('.profile_study_' + nr + ' input').val('qpa' + nr);
}
和细枝模板

<form action="#" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form) }}
    <input type="submit" value="Zapisz"/>
</form>
当我在表单中添加新的研究实体并将其发布到服务器时,我得到了一个错误:通过关系“Alden\xxxBundle\entity\Profile#Study”找到了一个新实体,该关系未配置为级联实体:Alden\xxxBundle\entity的持久化操作\Study@0000000073eb1a8b00000000198469ff. 显式持久化新实体或在关系上配置级联持久化操作。如果您无法找到导致问题的实体,请执行“Alden\xxxxBundle\entity\Study#uuu toString()”以获取线索

因此,我在配置文件中添加了级联:

/**
 * @var Study
 * @ORM\OneToMany(targetEntity="Study", mappedBy="profile", cascade={"persist"})
 */
private $study;
然后我得到了一个错误,比如在begining:SQLSTATE[23000]:完整性约束冲突:1048列“profile_id”不能为null

已编辑 我的控制器代码:

    $request = $this->getRequest();
    $r = $this->getProfileRepository();
    $profile = $id ? $r->find($id) : new \Alden\BonBundle\Entity\Profile();
    /* @var $profile \Alden\BonBundle\Entity\Profile */
    $form = $this->createForm(new ProfileType(), $profile);
    if ($request->getMethod() == 'POST')
    {
        $form->bindRequest($request);
        if ($form->isValid())
        {
            $vacation = $profile->getVacation();
            foreach($vacation as $v) {
                $r=5;
            }
            $em = $this->getEntityManager();
            $em->persist($profile);
            $em->flush();
            //return $this->redirect($this->generateUrl('profile_list'));
        }
    }
    return array(
        'profile' => $profile,
        'form' => $form->createView()
    );
解决方案

在Profile类中,重要的部分是级联、注释中的删除和setStudies()中的foreach循环(感谢suggestion@Parhs)

在学习课上

/**
 * @var Profile
 * @ORM\ManyToOne(targetEntity="Profile", inversedBy="studies")
 * @ORM\JoinColumn(name="profile_id", nullable=false, onDelete="CASCADE", referencedColumnName="profile_id")
 */
private $profile;

和常用的getter和setter。

如果我理解正确,您的关系是双向的,因此您必须指定拥有方反向方。作为原则2文件:

  • 反向侧必须使用OneToOne的mappedBy属性, 一对多或多对多映射声明
  • 拥有方必须使用OneToOne的inversedBy属性, ManyToOne或ManyToMany映射声明
  • 多数人永远是拥有方,少数人永远是拥有方 反向侧
所以我在第一次回答时就把你的联想搞砸了。在你的情况下,
Profile
必须是相反的一面,而研究应该是拥有的一面。但是您正在处理
配置文件
,因此需要配置文件上的
级联
注释来持久化新实体:

class Profile
{
    /**
     * Bidirectional (INVERSE SIDE)
     *
     * @ORM\OneToMany(targetEntity="Study", mappedBy="profile",
     *     cascade={"persist", "remove"})
     */
    private $studies;
}

class Study
{
    /**
     * Bidirectional (OWNING SIDE - FK)
     * 
     * @ORM\ManyToOne(targetEntity="Profile", inversedBy="studies")
     * @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
     */
    private $profile;
}

请注意,您的示例与Doctrine2文档中的示例完全相同。

您必须将profile设置为instance。在控制器中。您尚未粘贴控制器代码。。 您应该迭代$profile->getStudy集合并为每个项目设置->setProfile=$profile


那里发生的事情不适用于表单。他实际上有一个this reference。嗯,可能添加这是一种自动修复,以避免重复,不确定它是否有效,我将尝试使用您的解决方案。事实上,我已经建立了关系并定义了adder、remover、getter,在看到您的解决方案后,我添加了setter

但是,在提交表单时,没有调用我的setter

对我来说,解决办法是另一个

在adder方法中,我添加了一个调用来设置所有者

public function addStudie($studie)
{
     $studie->setProfile($this);
     $this->studies->add($studie);
}
要在提交表单时调用此加法器,需要将
by_reference
属性设置为
false
添加到表单集合字段

   $builder->add('study', 'collection', array(
                'type' => new StudyType(),
                'allow_add' => true,
                `by_reference` => false,
                'allow_delete' => true
                    )
            )
以下是文件:

类似地,如果您正在使用CollectionType字段,其中您的基础收集数据是一个对象(如Doctrine的ArrayCollection),那么如果您需要调用加法器和移除器(例如addAuthor()和removeAuthor()),则by_引用必须设置为false


@koral很抱歉我把自己的东西弄糟了。我将更新答案。我设法整理了拥有的东西,如你所见:)但问题仍然存在exists@koral查看我的编辑。我犯了一个错误——在您的具体案例中,对什么应该是拥有方/反向方有一些限制。查看我的更新答案并让我知道(它必须工作)。也不工作-仍在学习。profile_id=null。D2示例看起来与我的案例类似,但它是使用代码管理的,而不是使用Sf2表单。顺便说一句,在研究类中,我更改了引用列:@ORM\JoinColumn(nullable=false,onDelete=“CASCADE”,referencedColumnName=“profile\u id”)@Parths,基于示例,我添加了方法profile::addStudy(),但从未调用它。应该以某种方式激活吗?正如我告诉你的,你应该粘贴控制器代码。。您没有向我们显示控制器代码。它不是自动调用的!
/**
 * @var Profile
 * @ORM\ManyToOne(targetEntity="Profile", inversedBy="studies")
 * @ORM\JoinColumn(name="profile_id", nullable=false, onDelete="CASCADE", referencedColumnName="profile_id")
 */
private $profile;
class Profile
{
    /**
     * Bidirectional (INVERSE SIDE)
     *
     * @ORM\OneToMany(targetEntity="Study", mappedBy="profile",
     *     cascade={"persist", "remove"})
     */
    private $studies;
}

class Study
{
    /**
     * Bidirectional (OWNING SIDE - FK)
     * 
     * @ORM\ManyToOne(targetEntity="Profile", inversedBy="studies")
     * @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
     */
    private $profile;
}
public function addStudie($studie)
{
     $studie->setProfile($this);
     $this->studies->add($studie);
}
   $builder->add('study', 'collection', array(
                'type' => new StudyType(),
                'allow_add' => true,
                `by_reference` => false,
                'allow_delete' => true
                    )
            )