【问题标题】:Symfony / Doctrine: OneToMany insert results in null idSymfony / Doctrine:OneToMany 插入结果为空 id
【发布时间】:2017-12-29 22:10:49
【问题描述】:

我尝试将 OneToMany / ManyToOne 关系应用到两个实体(一个游戏有很多 GameContent)。

游戏

/**
 * @ORM\OneToMany(targetEntity="GameContent", mappedBy="game")
 */
private $contents;

public function __construct()
{
    $this->contents = new ArrayCollection();
}

public function getContents()
{
    return $this->contents;
}

游戏内容

/**
 * @ORM\ManyToOne(targetEntity="Game", inversedBy="contents")
 */
private $game;

下面的代码将两条记录插入到各自的表中:

$game = $form->getData();
$content = new GameContent();
$content->setType('some type');
$game->getContents()->add($content);

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

但是,GameContent 的game_id 插入为null

INSERT INTO game_content (type, game_id) VALUES (?, ?)
Parameters: { 1: 'some type', 2: null }

我也试过了:

  • 更改persist()的顺序
  • $game->getContents()->add($content) 替换为$game->addContents($content) 通过执行$this->contents[] = $content;
  • 删除 persist($content) 并在 Game 实体上添加 cascade={"persist"}

为什么game_id 被插入为空?


我目前的解决方法是:

$em = $this->getDoctrine()->getManager();

$game = $form->getData();
$em->persist($game);

$content = new GameContent();
$content->setType('some type');
$content->setGame($game);
$em->persist($content);

$em->flush();

【问题讨论】:

    标签: mysql symfony doctrine-orm symfony-2.8


    【解决方案1】:

    添加 setGame() 函数,强制关联:

    $game->addContent($this);
    

    并删除持久性:

    $em = $this->getDoctrine()->getManager();
    
    // Get data
    $game = $form->getData();
    
    // Create new GameContent and hydrate
    $content = new GameContent();
    $content->setType('some type');
    
    // Associate Game <> GameContent
    $content->setGame($game);
    
    // Persist Game and commit
    $em->persist($game);
    $em->flush();
    

    请注意,今天(Doctrine 2.7.1),make:entity 实用程序创建了为您执行此操作的方法,在您的情况下,您的游戏实体上会有这样的方法:

    public function addContent(GameContent $content): self
    {
        $this->contents->add($content);
        $content->setGame($this); // <-- IMPORTANT PART IS HERE
    
        return $this;
    }
    
    

    那么,在游戏中调用这个就可以了:

    this->addContent((new GameContent())->setType('some type'));
    

    【讨论】:

      【解决方案2】:

      您有 2 个解决方案:

      在控制器中保留子项

      没有cascade={"persist"}

      $em = $this->getDoctrine()->getManager();
      
      // Get data
      $game = $form->getData();
      
      // Create new GameContent and hydrate
      $content = new GameContent();
      $content->setType('some type');
      
      // Associate Game <> GameContent
      $content->setGame($game);
      
      // Persist GameContent
      $em->persist($content);
      
      // Persist Game and commit
      $em->persist($game);
      $em->flush();
      

      在级联中坚持孩子

      cascade={"persist"} 在 OneToMany 关系中。

      添加setGame()函数,强制关联:

      $game->addContent($this);
      

      并删除持久性:

      $em = $this->getDoctrine()->getManager();
      
      // Get data
      $game = $form->getData();
      
      // Create new GameContent and hydrate
      $content = new GameContent();
      $content->setType('some type');
      
      // Associate Game <> GameContent
      $content->setGame($game);
      
      // Persist Game and commit
      $em->persist($game);
      $em->flush();
      

      我认为这个错误也是由于游戏坚持的定位。

      【讨论】:

      • 啊,所以我为了级联而错过了$game-&gt;addContent($this);。通常首选这两种解决方案吗?
      • 顺便说一句,游戏中持久化的定位似乎并不重要(请参阅我的“解决方法”,它与您的第一个解决方案相同,但持久化顺序不同)。
      【解决方案3】:

      除了接受的答案之外,我的下一步是创建一个表单来处理 GameContent 数据,这导致了进一步的更改和一些简化的逻辑。

      我现在在Game::addContent() 中添加了setGame(),因此我在GameContent::setGame() 中删除了$game-&gt;addContent($this);

      游戏

      /**
       * @var ArrayCollection
       * @ORM\OneToMany(targetEntity="GameContent", mappedBy="game", cascade={"persist"})
       */
      private $contents;
      
      public function __construct()
      {
          $this->contents = new ArrayCollection();
      }
      
      public function getContents()
      {
          return $this->contents;
      }
      
      public function addContent(GameContent $content)
      {
          $this->contents->add($content);
          $content->setGame($this);
      
          return $this;
      }
      
      public function removeContent(GameContent $content)
      {
          $this->contents->removeElement($content);
      
          return $this;
      }
      

      游戏内容

      /**
       * @ORM\ManyToOne(targetEntity="Game", inversedBy="contents")
       */
      private $game;
      
      public function setGame(Game $game)
      {
          $this->game = $game;
      
          return $this;
      }
      
      /**
       * @return Game
       */
      public function getGame()
      {
          return $this->game;
      }
      

      现实世界的表单处理逻辑如下所示:

      $game = $form->getData();
      $em = $this->getDoctrine()->getManager();
      $em->persist($game);
      $em->flush();
      

      更多信息请访问:http://symfony.com/doc/2.8/form/form_collections.html(参见学说:级联关系和保存“逆”端)。

      【讨论】:

        猜你喜欢
        • 2023-03-28
        • 2014-06-18
        • 2022-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-22
        相关资源
        最近更新 更多