我有个人资料和研究。一个人可以完成很多研究。表单呈现正确。有一个按钮“添加新的研究”和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;
...
}
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`);
Form 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);
}
和Twig模板
<form action="#" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" value="Zapisz"/>
</form>
出于测试目的,我在study.profile_id上删除了数据库约束NOT NULL,然后保存了除了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;
当我在表单中添加新的Study实体并将其发布到服务器时出现错误:通过关系'Alden \ xxxBundle \ Entity \ Profile#study'找到了一个新实体,该关系未配置为级联持久化操作实体:Alden \ xxxBundle \ Entity \ Study @ 0000000073eb1a8b00000000198469ff。明确保留新实体或在关系上配置级联持久操作。如果您无法找出导致问题的实体,请执行'Alden \ xxxxBundle \ Entity \ Study #__ 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,setStudies()中的foreach循环(感谢建议@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;
和通常的吸气者和制定者。
答案 0 :(得分:3)
如果我理解正确您的关系是双向的,那么您必须指定拥有方和反面。作为Doctrine 2文档:
所以我在第一个答案中搞砸了你的协会。在你的情况下,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文档中的that完全相同。
答案 1 :(得分:1)
您必须将个人资料设置为实例。在控制器中。你还没有粘贴控制器代码.. 您应该遍历$ profile-&gt; getStudy集合并为每个项目设置 - &gt; setProfile = $ profile。
那里发生的事情并不适用于表格..他实际上有一个这样的参考......也许添加这是一种自动修复以避免迭代,不确定它是否有效,我会尝试
答案 2 :(得分:0)
您的解决方案对我不起作用。事实上,我已经建立了关系,并定义了加法器,移除器,吸气器,在看到你的解决方案后,我添加了设置器。
然而,在提交表单时没有调用我的setter。
我的解决方案是另一个。
在加法器方法中,我添加了一个设置所有者的调用。
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一样),那么如果您需要加法器和移除器,则必须将by_reference设置为false(例如,要调用的addAuthor()和removeAuthor())。
http://symfony.com/doc/current/reference/forms/types/collection.html#by-reference