簡體   English   中英

Symfony 3:嵌入表單集合的持久性問題:違反完整性約束:1048列“ arrivage_id”不能為空

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

我正在使用Symfony 3.4 lts ,但是嵌入式集合表單持久性出現問題。

此問題要求Symfony Expert ..該描述看起來很長,但是它是Symofny CLI默認命令自動生成的代碼的80%。

我是還原專家,因此您會發現我的描述簡單且具有教學意義,

這個簡單的UML圖類描述了我的3個實體

在此處輸入圖片說明

代碼是法語,因此Arrival是Arrivage,product是Produit,中間實體ArrivalElement是ElementArrivage。

實體: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

實體: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

實體: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

形式: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
            )
        ))
        ;

    }/**

形式: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,
        ));
        ;
    }/*

所以我的主要實體是到達,我必須創建一個到達,它必須在Cascade上保持其余部分,以便我必須為到達實體創建一個控制器

ArrivageController:

經理論產生結垢后仍然干凈

視圖:

我使用文檔技術(原型)來創建新的elementArrivage

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

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

問題:

使用這種配置,在嘗試創建新的到達時,我遇到了第一個持久性問題:

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

我通過在方法的“實體到達”中添加一行來解決此問題:

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

    return $this;
}

第一個問題:這是一個適當的解決方案嗎?

解決了第一個問題之后,我得到了第二個問題:

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

第二個問題:我對解決方案一無所知,但是當我嘗試使用此行修改Controller時,問題消失了,但這不是解決方案,因為在這種情況下ElementArrivage將固定為兩個:

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(),
    ));
}

關於您的問題,是否手動將父母添加到孩子以便識別雙向關聯是正確的方法。 是的。

至於第二個問題。 似乎Doctrine無法說出,它需要在持久化到達元素之前先持久化到達,從而導致您面臨的null id問題。 您可以通過指定如下所示的表單的data_class來解決此問題,以確保表單返回正確的元素:

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

即使那樣,您的實體也可能不受教義管理,因為您是手動創建它們的。 由於Symfony Form嘗試使用類的getter和setter,因此當Arrivage類具有此類setter時,它應該識別實體並也將其持久化:

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

您可能還必須堅持不指定實體,所以只需$em->persist(); 而不是$em->persist($arrivage); 在您的控制器中;

如果所有這些都不起作用,請嘗試使用xdebug查看元素是否在實體管理器的工作單元中。 如果沒有,您可以隨時手動保留它們:

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

當您必須手動控制像這樣的教義時,通常表明您正在做某事超出其想做的事情以及它在哪里表現良好。 您可能需要考慮重新組織域/表映射。

謝謝@dhrumann的合作對我非常有益,現在我知道doctrine:generate:crud僅提供了控制器的主要框架,而不是完全適合我情況的控制器。

因此,對於我的代碼中正確提到的data_class(由doctrine:generate:crud自動生成)

關於您的最后一個代碼段,我認為這不是邏輯,因為您試圖在持久化作為其自身父級的(Arrivage)之前持久化包含arrivage_id的(ElementsArrivage)。 因此,arrivage_id將為null,這將導致我認為的問題。 你確認嗎?

我采用的解決方案是:(請參閱//添加的塊)

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM