简体   繁体   English

Symfony 3:嵌入表单集合的持久性问题:违反完整性约束:1048列“ arrivage_id”不能为空

[英]Symfony 3 : Embed Collection of Forms persistence issue : Integrity constraint violation: 1048 Column 'arrivage_id' cannot be null

I'm working with Symfony 3.4 lts and I get an issue with Embedded Collection Forms persistance. 我正在使用Symfony 3.4 lts ,但是嵌入式集合表单持久性出现问题。

This Issue requries a Symfony Expert .. The description seems long somewhere but it's 80% of code generated automatically by Symofny CLI default commands. 此问题要求Symfony Expert ..该描述看起来很长,但是它是Symofny CLI默认命令自动生成的代码的80%。

I'm a reduction expert so You will find that my description is simple and pedagogical, 我是还原专家,因此您会发现我的描述简单且具有教学意义,

My 3 entities are described with this simple UML Diagram Class 这个简单的UML图类描述了我的3个实体

在此处输入图片说明

The code is in french so Arrival is Arrivage, product is Produit and the intermediate entity ArrivalElement is ElementArrivage. 代码是法语,因此Arrival是Arrivage,product是Produit,中间实体ArrivalElement是ElementArrivage。

Entity: Arrivage.php (Arrival in english) 实体:Arrivage.php(英语到达)

/**
 * Arrivage
 *
 * @ORM\Table(name="arrivage")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ArrivageRepository")
 */
class Arrivage
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="dateCreation", type="datetime")
     */
    private $dateCreation;

    /**
     * @var Arrivage
     * @ORM\OneToMany(targetEntity="ElementArrivage", mappedBy="arrivage", cascade={"persist", "remove"}, orphanRemoval=TRUE)
     */
    private $elementArrivages;

    public function __construct() {
      $this->dateCreation = new \DateTime();
      $this->elementArrivages = new ArrayCollection();
    }

// bin/console doctrine:generate:entities AppBundle:Arrivage => OK

Entity: ElementArrivage (intermediate entity created for the Many To Many relation with extra field) 实体:ElementArrivage(为带有额外字段的多对多关系创建的中间实体)

/**
 * ElementArrivage
 *
 * @ORM\Table(name="element_arrivage")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ElementArrivageRepository")
 */
class ElementArrivage
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;


    /**
     * @var Arrivage
     *
     * @ORM\ManyToOne(targetEntity="Arrivage", inversedBy="elementArrivages")
     * @ORM\JoinColumn(name="arrivage_id", referencedColumnName="id", nullable=FALSE)
     */
     private $arrivage;

     /**
      * @var Produit
      *
      * @ORM\ManyToOne(targetEntity="Produit", inversedBy="elementArrivages")
      * @ORM\JoinColumn(name="produit_id", referencedColumnName="id", nullable=FALSE)
      */
      private $produit;

    /**
     * @var int
     *
     * @ORM\Column(name="quantite", type="integer")
     */
    private $quantite;

    /**
     * @var string
     *
     * @ORM\Column(name="prix_achat", type="decimal", precision=10, scale=3)
     */
    private $prixAchat;

// bin/console doctrine:generate:entities => OK

Entity: Produit.php: 实体:Produit.php:

/**
 * Produit
 *
 * @ORM\Table(name="produit")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ProduitRepository")
 */
class Produit
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, unique=true)
     */
    private $name;

     /**
      * @var Arrivage
      * @ORM\OneToMany(targetEntity="ElementArrivage", mappedBy="produit", cascade={"persist", "remove"}, orphanRemoval=TRUE)
      */
     private $elementArrivages;

// bin/console doctrine:generate:entities => OK

Form: ArrivageType.php: 形式:ArrivageType.php:

class ArrivageType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
        ->add('elementArrivages', CollectionType::class, array(
            'entry_type' => ElementArrivageType::class,
            'allow_add' => true,
            'allow_delete' => true,
            'label'=> false,
            'entry_options' => array(
              'label' => false
            )
        ))
        ;

    }/**

Form: ElementArrivage.php: 形式:ElementArrivage.php:

class ElementArrivageType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
        ->add('quantite')
        ->add('prixAchat')
        ->add('produit', EntityType::class, array(
            // looks for choices from this entity
            'class' => 'AppBundle:Produit',

            // uses the User.username property as the visible option string
            'choice_label' => 'name',

            // used to render a select box, check boxes or radios
            // 'multiple' => true,
            // 'expanded' => true,
        ));
        ;
    }/*

So my principal Entity is arrival, I have to create an arrival and it must persist the rest onCascade, So that I have to create a controller only for arrival entity 所以我的主要实体是到达,我必须创建一个到达,它必须在Cascade上保持其余部分,以便我必须为到达实体创建一个控制器

ArrivageController: ArrivageController:

it still clean after generating crud by doctrine 经理论产生结垢后仍然干净

View: 视图:

I used documentation technique ( prototype ) to allow create new elementArrivage 我使用文档技术(原型)来创建新的elementArrivage

Doc: https://symfony.com/doc/3.4/form/form_collections.html#allowing-new-tags-with-the-prototype 文件: https//symfony.com/doc/3.4/form/form_collections.html#allowing-new-tags-with-the-prototype

Demo javascript: http://jsfiddle.net/847Kf/4/ 演示javascript: http//jsfiddle.net/847Kf/4/

ISSUES: 问题:

With this configuration While Trying to create a new arrival I get a first persistance issue: 使用这种配置,在尝试创建新的到达时,我遇到了第一个持久性问题:

An exception occurred while executing 'INSERT INTO element_arrivage (quantite, prix_achat, prixVente, arrivage_id, produit_id) VALUES (?, ?, ?, ?, ?)' with params [1, 1, 1, null, 11]:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'arrivage_id' cannot be null

I resolved this issue by adding a line in Entity Arrivage in the method: 我通过在方法的“实体到达”中添加一行来解决此问题:

public function addElementArrivage(\AppBundle\Entity\ElementArrivage $elementArrivage)
{
    $elementArrivage->setArrivage($this); // Added Liiiiiiiiiiiiiiiiiiine
    $this->elementArrivages[] = $elementArrivage;

    return $this;
}

First Question: Is this a proper Solution ??? 第一个问题:这是一个适当的解决方案吗?

After resolving the first issue, I get the second Issue: 解决了第一个问题之后,我得到了第二个问题:

An exception occurred while executing 'INSERT INTO element_arrivage (quantite, prix_achat, prixVente, arrivage_id, produit_id) VALUES (?, ?, ?, ?, ?)' with params [1, 1, 1, null, 11]:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'arrivage_id' cannot be null

Second Question: I doesn't have any idea about the solution but When I tried to modify the Controller with this line the problem disappears but it's not a solution because in this case the ElementArrivage will be fixed to two: 第二个问题:我对解决方案一无所知,但是当我尝试使用此行修改Controller时,问题消失了,但这不是解决方案,因为在这种情况下ElementArrivage将固定为两个:

ArrivageController: ArrivageController:

/**
 * Creates a new arrivage entity.
 *
 * @Route("/new", name="arrivage_new")
 * @Method({"GET", "POST"})
 */
public function newAction(Request $request)
{
    $arrivage = new Arrivage();
    $elementArrivage = new ElementArrivage();   //Added Liiiiines begin
    $elementArrivage2 = new ElementArrivage();
    $arrivage->addElementArrivage($elementArrivage);
    $arrivage->addElementArrivage($elementArrivage2); // Added Liiiines end

    $form = $this->createForm('AppBundle\Form\ArrivageType', $arrivage);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {

        $em = $this->getDoctrine()->getManager();
        $em->persist($arrivage);
        $em->flush();

        return $this->redirectToRoute('arrivage_show', array('id' => $arrivage->getId()));
    }

    return $this->render('arrivage/new.html.twig', array(
        'arrivage' => $arrivage,
        'form' => $form->createView(),
    ));
}

Regarding your question on whether manually adding the parent to the child in order for the bi-directional association to be recognized is the right way to do it. 关于您的问题,是否手动将父母添加到孩子以便识别双向关联是正确的方法。 Yes it is. 是的。

As for your second question. 至于第二个问题。 It seems that Doctrine is not able to tell, that it needs to persist the arrivals before it persists the arrival elements, leading to the null id problem you are facing. 似乎Doctrine无法说出,它需要在持久化到达元素之前先持久化到达,从而导致您面临的null id问题。 You might be able to solve this by specifying the data_class of your forms like below, to make sure your forms return the correct elements: 您可以通过指定如下所示的表单的data_class来解决此问题,以确保表单返回正确的元素:

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => ElementArrivage::class,
    ));
}

Even then your entities might not be managed by Doctrine, as you created them manually. 即使那样,您的实体也可能不受教义管理,因为您是手动创建它们的。 Since Symfony Form tries to use the getters and setters of your class, when your Arrivage-class has a setter like this, it should recognize the entities and persist them as well: 由于Symfony Form尝试使用类的getter和setter,因此当Arrivage类具有此类setter时,它应该识别实体并也将其持久化:

public function setElementArrivages($elements)
{
    foreach($elements as $element) {
        $this->addElementArrivage($element); // the method from your example
    }
}

You might also have to persist without specifying an entity, so just $em->persist(); 您可能还必须坚持不指定实体,所以只需$em->persist(); instead of $em->persist($arrivage); 而不是$em->persist($arrivage); in your controller; 在您的控制器中;

If all this does not work try using xdebug to see if the elements are in the unit of work (uow) of the entity manager. 如果所有这些都不起作用,请尝试使用xdebug查看元素是否在实体管理器的工作单元中。 If not, you could always manually persist them: 如果没有,您可以随时手动保留它们:

if ($form->isSubmitted() && $form->isValid()) {
    $elements = $arrivage->getElementArrivages();
    foreach ($elements as $element) {
        $em->persist($element);
    }
    $em->persist($arrivage);
    $em->flush();
}

When you have to manually have to control Doctrine like this, it usually is a sign that you are doing something that's outside what it wants to do and where it performs well. 当您必须手动控制像这样的教义时,通常表明您正在做某事超出其想做的事情以及它在哪里表现良好。 You might want to look into reorganizing your domain/table mapping. 您可能需要考虑重新组织域/表映射。

Thank you @dhrumann for your collaboration that was very benefice for me, Now I know that doctrine:generate:crud provides only the primary skeleton of a controller and not a Controller perfectly adapted to my situation. 谢谢@dhrumann的合作对我非常有益,现在我知道doctrine:generate:crud仅提供了控制器的主要框架,而不是完全适合我情况的控制器。

So, for data_class that was correctly mentioned in my code (automatically generated by doctrine:generate:crud) 因此,对于我的代码中正确提到的data_class(由doctrine:generate:crud自动生成)

Regarding your last code section,I think it isn't logic because you are trying to persist (ElementsArrivage) which contains arrivage_id before persisting the (Arrivage) which is the parent its self. 关于您的最后一个代码段,我认为这不是逻辑,因为您试图在持久化作为其自身父级的(Arrivage)之前持久化包含arrivage_id的(ElementsArrivage)。 So the arrivage_id will be null and it will causes an issue I think. 因此,arrivage_id将为null,这将导致我认为的问题。 Do you confirm ? 你确认吗?

The Solution I adapt is: (see //Added Block) 我采用的解决方案是:(请参阅//添加的块)

ArrivageController: ArrivageController:

public function newAction(Request $request){

$arrivage = new Arrivage();

$form = $this->createForm('AppBundle\Form\ArrivageType', $arrivage);
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {

    //Added Block Begiiiiiiin
    $elementArrivages = $arrivage->getElementArrivages();
    foreach( $elementArrivages as $elementArrivage){
      $elementArrivage->setArrivage($arrivage);
    }
    //Added Block Ennnnnd

    $em = $this->getDoctrine()->getManager();
    $em->persist($arrivage);
    $em->flush();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用Doctrine和Symfony获取“完整性约束违规:1048列'payment_id'不能为空” - Getting “Integrity constraint violation: 1048 Column 'payment_id' cannot be null” using Doctrine & Symfony 违反完整性约束:1048列“ user_id”不能为空 - Integrity constraint violation: 1048 Column 'user_id' cannot be null 违反完整性约束:1048列“ announcement_id”不能为空 - Integrity constraint violation: 1048 Column 'announcement_id' cannot be null Symfony 3.4 OneToMany SQLSTATE [23000]:违反完整性约束:1048列“ shopping_list_id”不能为空 - Symfony 3.4 OneToMany SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'shopping_list_id' cannot be null Symfony 5 执行查询时发生异常:SQLSTATE [23000]:完整性约束违规:1048 列“名称”不能为 null - Symfony 5 An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null SQLSTATE [23000]:违反完整性约束:1048列“ idzwierzatka”不能为空 - SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'idzwierzatka' cannot be null SQLSTATE [23000]:违反完整性约束:1048 列 'id_utilisateur_id' 不能为空 - SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'id_utilisateur_id' cannot be null 执行查询时发生异常:SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'pokemon_id' cannot be null - An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'pokemon_id' cannot be null SQLSTATE [23000]:违反完整性约束:1048列“ ent_text”不能为空 - SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'ent_text' cannot be null 违反Symfony完整性约束 - Symfony Integrity constraint violation
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM