Symfony2的形式和Doctrine2 - 在指定的实体更新外键失败(Symfony2 for

2019-06-24 10:21发布

我拥有个人资料和研究。 一个人可以完成很多研究。 形式正确呈现。 有一个按钮“添加新的研究”,并与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();
    }
...
}

    class Study {
    /**
     * @var integer $studyId
     *
     * @ORM\Column(name="study_id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $studyId;
...
    /**
     * @var Profile
     *
     * @ORM\ManyToOne(targetEntity="Profile")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="profile_id", referencedColumnName="profile_id")
     * })
     */
    private $profile;
...
}

以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`);

表buidlers是:

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
                        )
                )
    }
...
}

class StudyType extends AbstractType {

    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
                ->add('city') //example field not included in above structures
    }
...
}

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>

出于测试目的,我从数据库约束NOT NULL上study.profile_id删除,然后一切都被保存,除了study.profile_id = NULL。

@Gremo答案后编辑

我做了一些测试。 遗憾的是它并没有帮助:(我纠正了自己的错误,代码

class Profile
    /**
     * @var Study
     * @ORM\OneToMany(targetEntity="Study", mappedBy="profile")
     */
    private $study;
class Study
    /**
     * @var Profile
     * @ORM\ManyToOne(targetEntity="Profile", inversedBy="study")
     * @ORM\JoinColumn(nullable=false, onDelete="CASCADE", referencedColumnName="profile_id")
     */
    private $profile;

当我在形式上增加了新的研究实体,并将其发布到服务器我得到了一个错误:一个新的实体通过中没有配置级联持续经营为实体的关系“奥尔登\ xxxBundle \实体\档案#研究的发现:奥尔登\ xxxBundle \实体\研究@ 0000000073eb1a8b00000000198469ff。 明确坚持新实体或级联配置上仍然存在的关系操作。 如果你不能找出哪些实体引起该问题实行“奥尔登\ xxxxBundle \实体\研究#__的toString()”,以获得一个线索。

所以我加了级联的个人资料:

/**
 * @var Study
 * @ORM\OneToMany(targetEntity="Study", mappedBy="profile", cascade={"persist"})
 */
private $study;

比我得到了一个错误,如在开始时:SQLSTATE [23000]:完整性约束违规:1048列“PROFILE_ID”不能为空。

编辑我的控制器代码:

    $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类,重要的部分是级联,orphanRemoval在注释和foreach循环中setStudies()(感谢建议@Parhs)

/**
 * @var \Doctrine\Common\Collections\ArrayCollection
 * @ORM\OneToMany(targetEntity="Study", mappedBy="profile", cascade={"ALL"}, orphanRemoval=true)
 */
private $studies;

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

/**
 * @return Doctrine\Common\Collections\Collection
 */
public function getStudies()
{
    return $this->studies;
}

public function setStudies($studies)
{
    foreach ($studies as $v)
    {
        if (is_null($v->getProfile()))
        {
            $v->setProfile($this);
        }
    }
    $this->studies = $studies;
}

在学习班

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

和通常的getter和setter。

Answer 1:

如果我理解正确的话你的关系是双向的,所以你必须指定一个拥有方反侧 。 作为学说2文档:

  • 逆侧具有使用OneToOne,一对多的属性的mappedBy,或多对多映射声明
  • 所属侧具有使用OneToOne,多对一,或多对多映射声明的inversedBy属性
  • 多对一总是拥有方和一对多总是反侧

所以我搞砸了,我先回答你的关联。 你的情况Profile必须是逆一边学习应该是拥有方。 但是,您正在使用的Profile ,所以您需要的cascade上的配置文件注释坚持新的实体:

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文档。



Answer 2:

你必须配置文件设置为实例。 在控制器。 您还没有粘贴控制器代码。您应该遍历$简介 - > getStudy收集,并对每个项目设置 - > setProfile = $配置文件。

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes

正在发生的事情有犯规适用于forms..He居然有这种reference..Hm也许添加这是一种自动修复,以避免重复,不知道它是否有效,我会尽力



Answer 3:

您的解决方案并没有为我工作。 其实我已经建立了关系,并定义了加法,卸妆,getter和我看到您的解决方案后,我加入的制定者。

但是提交表单的时候不叫我的二传手。

对我来说,解决方案是另外一个。

在加法器方法我添加了一个呼叫设置所有者。

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场在您的底层集合数据对象(像学说的ArrayCollection的),然后by_reference必须,如果你需要的加法器和卸妆设置为false(如addAuthor()和removeAuthor())来叫做。

http://symfony.com/doc/current/reference/forms/types/collection.html#by-reference



文章来源: Symfony2 form and Doctrine2 - update foreign key in assigned entities fails