У меня есть два объекта, которые я пытаюсь применить отношение OneToMany/ManyToOne (в одной игре есть много GameContent).
Игра
/**
* @ORM\OneToMany(targetEntity="GameContent", mappedBy="game")
*/
private $contents;
public function __construct()
{
$this->contents = new ArrayCollection();
}
public function getContents()
{
return $this->contents;
}
GameContent
/**
* @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)
и наличие cascade={"persist"}
в игровом объекте. Почему game_id
вставляется как null?
Мое текущее решение:
$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();
У вас есть 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"}
persist cascade={"persist"}
в отношении OneToMany.
Добавьте в setGame()
, чтобы принудительно установить связь:
$game->addContent($this);
И удалить 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 Game and commit
$em->persist($game);
$em->flush();
Я думаю, что ошибка также была связана с позиционированием сохраняющейся игры.
В дополнение к принятому ответу, моим следующим шагом было создание формы для обработки данных GameContent, что привело к дальнейшим изменениям и некоторой упрощенной логике.
Я теперь setGame()
в Game::addContent()
, и поэтому я удалил $game->addContent($this);
в GameContent::setGame()
.
Игра
/**
* @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;
}
GameContent
/**
* @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 (см. Доктрина: Каскадные отношения и сохранение "Обратная").
$game->addContent($this);
для того, чтобы каскадировать. Является ли любое решение в целом предпочтительным?