持久插入 OneToMany ArrayCollection 变量中的所有数据
A persist insert all data from OneToMany ArrayCollection variable
我在尝试保留数据时遇到错误,但我没有找到关于遇到完全相同问题的人的帮助....
我有两个 linked 实体 score(ManyToOne)/player(OneToMany) 当我坚持 score, doctrine 插入我要存储的分数对应的player的数组集合$scores中存储的所有分数。
作为参考,我存储了一轮的每个分数,所以一个用户有多个分数(所以 manyToOne/OneToMany 关系)。
我有一份包含所有分数的球员名单。我只想插入最后一个,就像其他人已经在数据库中一样。但是对于我尝试过的每个解决方案,原则都会插入所有分数......即使我只将最后一个分数放在玩家分数中。
然后,我删除了每个实体上的持久级联,学说在实体上抛出关于 link 的异常...
这是分数实体
/**
* Score
*
* @ORM\Table(name="score")
* @ORM\Entity(repositoryClass="AppBundle\Entity\Repository\ScoreRepository")
*/
class Score
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Player", inversedBy="scores", cascade={"persist"})
* @ORM\JoinColumn(name="player", referencedColumnName="id")
*
* @var Player
*/
private $player;
/**
* @var DateTime
*
* @ORM\Column(name="played_at", type="datetime")
*/
private $playedAt;
/**
* @var int
*
* @ORM\Column(name="value", type="integer")
*/
private $value;
这是玩家实体:
/**
* Player
*
* @ORM\Table(name="player")
* @ORM\Entity(repositoryClass="AppBundle\Entity\Repository\PlayerRepository")
*/
class Player extends BaseUser
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
*
* @ORM\Column(name="firstname", type="string", length=255)
*/
private $firstname;
/**
* @var string
*
* @ORM\Column(name="lastname", type="string", length=255)
*/
private $lastname;
/**
* @var string
*
* @ORM\Column(name="job", type="string", length=255)
*/
private $job;
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Score", mappedBy="player", cascade={"persist"})
*
* @var ArrayCollection|Score[]
*/
private $scores;
这是现在,我想要保存分数的控制器
$content = $request->getContent();
$scoresParams = [];
if (!empty($content))
{
$scoresParams = json_decode($content, true); // 2nd param to get as array
}
$players = array();
$transformer = $this->get('app.transformer.score');
foreach($scoresParams as $k=>$v) {
$players[] = $transformer->reverseTransform($v);
}
foreach($players as $k=>$p) {
$index = count($p->getScores()) - 1;
$s = $p->getScores()[$index];
$p->setScores(array($s));
$this->get('app.repository.score')->persist($s);
}
我只用我想保存的分数来设置玩家分数...因为,就像我坚持使用 cascad,而所有其他用户的分数都不是从学说中检索的,hit 会尝试插入他们...
所以,对于第一个玩家,好的,但是对于第二个,$s 在我持久化它的时候已经有一个 ID,并且它持久化了玩家的所有数据(不仅仅是最后一个)。
转换器是一个包 (League\Fractal\Transformer),它根据一组数据创建一组玩家
public function reverseTransform(array $data)
{
$this->checkRequiredFields($data);
$player = $this->playerRepository->find($data[self::KEY_ID]);
if (!$player) {
throw new NotFoundException('User not found');
}
$scoresRaw = $data[self::KEY_ENC_SCORES];
$scores = array();
foreach($scoresRaw as $k => $s) {
$score = new Score($player);
if($s[self::KEY_ENC_SCORE_ID] != 0) {
$score->setId($s[self::KEY_ENC_SCORE_ID]);
}
$score->setPlayedAt( ( new \DateTime() )->setTimestamp( $s[self::KEY_ENC_SCORE_DATE] ) );
$score->setValue($s[self::KEY_ENC_SCORE_VALUE]);
$scores[] = $score;
}
$player->setScores($scores);
return $player;
}
你能看出这里出了什么问题吗?
这是解决方案
-> 控制器
$content = $request->getContent();
$scoresParams = [];
if (!empty($content))
{
$scoresParams = json_decode($content, true); // 2nd param to get as array
}
$players = array();
$transformer = $this->get('app.transformer.score');
// For each players
foreach($scoresParams as $i=>$player) {
$scores = $player['scores'];
foreach($scores as $j=>$s) {
$score = $transformer->reverseTransform($s['data']);
$this->get('app.repository.score')->merge($score);
}
}
$response = new JsonResponse(array('data' => ''));
$response->setStatusCode(201);
return $response;
以及将分数数组反转为对象的函数
$player = $this->playerRepository->find($data[self::KEY_USER]);
if (!$player) {
throw new NotFoundException('User not found');
}
$score = new Score($player);
if($data[self::KEY_ID] != 0) {
$score->setId($data[self::KEY_ID]);
}
$score->setPlayedAt( ( new \DateTime() )->setTimestamp( $data[self::KEY_DATE] ) );
$score->setValue($data[self::KEY_VALUE]);
return $score;
由于您的实体来自 json,它不会 link 发送到实体管理器。
我认为你应该使用 merge()
方法来 link 它。
$score->setValue($s[self::KEY_ENC_SCORE_VALUE]);
$this->get('app.repository.score')->merge($score);
$scores[] = $score;
}
$player->setScores($scores);
我在尝试保留数据时遇到错误,但我没有找到关于遇到完全相同问题的人的帮助....
我有两个 linked 实体 score(ManyToOne)/player(OneToMany) 当我坚持 score, doctrine 插入我要存储的分数对应的player的数组集合$scores中存储的所有分数。 作为参考,我存储了一轮的每个分数,所以一个用户有多个分数(所以 manyToOne/OneToMany 关系)。
我有一份包含所有分数的球员名单。我只想插入最后一个,就像其他人已经在数据库中一样。但是对于我尝试过的每个解决方案,原则都会插入所有分数......即使我只将最后一个分数放在玩家分数中。 然后,我删除了每个实体上的持久级联,学说在实体上抛出关于 link 的异常...
这是分数实体
/**
* Score
*
* @ORM\Table(name="score")
* @ORM\Entity(repositoryClass="AppBundle\Entity\Repository\ScoreRepository")
*/
class Score
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Player", inversedBy="scores", cascade={"persist"})
* @ORM\JoinColumn(name="player", referencedColumnName="id")
*
* @var Player
*/
private $player;
/**
* @var DateTime
*
* @ORM\Column(name="played_at", type="datetime")
*/
private $playedAt;
/**
* @var int
*
* @ORM\Column(name="value", type="integer")
*/
private $value;
这是玩家实体:
/**
* Player
*
* @ORM\Table(name="player")
* @ORM\Entity(repositoryClass="AppBundle\Entity\Repository\PlayerRepository")
*/
class Player extends BaseUser
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
*
* @ORM\Column(name="firstname", type="string", length=255)
*/
private $firstname;
/**
* @var string
*
* @ORM\Column(name="lastname", type="string", length=255)
*/
private $lastname;
/**
* @var string
*
* @ORM\Column(name="job", type="string", length=255)
*/
private $job;
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Score", mappedBy="player", cascade={"persist"})
*
* @var ArrayCollection|Score[]
*/
private $scores;
这是现在,我想要保存分数的控制器
$content = $request->getContent();
$scoresParams = [];
if (!empty($content))
{
$scoresParams = json_decode($content, true); // 2nd param to get as array
}
$players = array();
$transformer = $this->get('app.transformer.score');
foreach($scoresParams as $k=>$v) {
$players[] = $transformer->reverseTransform($v);
}
foreach($players as $k=>$p) {
$index = count($p->getScores()) - 1;
$s = $p->getScores()[$index];
$p->setScores(array($s));
$this->get('app.repository.score')->persist($s);
}
我只用我想保存的分数来设置玩家分数...因为,就像我坚持使用 cascad,而所有其他用户的分数都不是从学说中检索的,hit 会尝试插入他们... 所以,对于第一个玩家,好的,但是对于第二个,$s 在我持久化它的时候已经有一个 ID,并且它持久化了玩家的所有数据(不仅仅是最后一个)。
转换器是一个包 (League\Fractal\Transformer),它根据一组数据创建一组玩家
public function reverseTransform(array $data)
{
$this->checkRequiredFields($data);
$player = $this->playerRepository->find($data[self::KEY_ID]);
if (!$player) {
throw new NotFoundException('User not found');
}
$scoresRaw = $data[self::KEY_ENC_SCORES];
$scores = array();
foreach($scoresRaw as $k => $s) {
$score = new Score($player);
if($s[self::KEY_ENC_SCORE_ID] != 0) {
$score->setId($s[self::KEY_ENC_SCORE_ID]);
}
$score->setPlayedAt( ( new \DateTime() )->setTimestamp( $s[self::KEY_ENC_SCORE_DATE] ) );
$score->setValue($s[self::KEY_ENC_SCORE_VALUE]);
$scores[] = $score;
}
$player->setScores($scores);
return $player;
}
你能看出这里出了什么问题吗?
这是解决方案 -> 控制器
$content = $request->getContent();
$scoresParams = [];
if (!empty($content))
{
$scoresParams = json_decode($content, true); // 2nd param to get as array
}
$players = array();
$transformer = $this->get('app.transformer.score');
// For each players
foreach($scoresParams as $i=>$player) {
$scores = $player['scores'];
foreach($scores as $j=>$s) {
$score = $transformer->reverseTransform($s['data']);
$this->get('app.repository.score')->merge($score);
}
}
$response = new JsonResponse(array('data' => ''));
$response->setStatusCode(201);
return $response;
以及将分数数组反转为对象的函数
$player = $this->playerRepository->find($data[self::KEY_USER]);
if (!$player) {
throw new NotFoundException('User not found');
}
$score = new Score($player);
if($data[self::KEY_ID] != 0) {
$score->setId($data[self::KEY_ID]);
}
$score->setPlayedAt( ( new \DateTime() )->setTimestamp( $data[self::KEY_DATE] ) );
$score->setValue($data[self::KEY_VALUE]);
return $score;
由于您的实体来自 json,它不会 link 发送到实体管理器。
我认为你应该使用 merge()
方法来 link 它。
$score->setValue($s[self::KEY_ENC_SCORE_VALUE]);
$this->get('app.repository.score')->merge($score);
$scores[] = $score;
}
$player->setScores($scores);