Doctrine ORM无法持久化ManyToMany的一端(SQLSTATE [23000]:UNIQUE约束违规)

时间:2018-05-24 21:31:25

标签: doctrine-orm orm doctrine symfony4

我是Symfony 4和Doctrine的新人(ish)所以也许我对Doctrine ORM抱有太多期待,但事实上我无法找到合适的文档告诉我我疯了!

错误

SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: skill.id

摘要 我在玩家和技能实体之间创建了ManyToMany关系。这些实体中的每一个都手动设置其ID,因为它们来自外部API。我正在构建PlayerController中的数据,它会擦除​​第三方API以在我的数据库中本地缓存数据。

我写的代码允许在我的数据库中存储(缓存)第三方数据,如果添加的技能尚未添加到数据库中。但是,如果我尝试添加另一个共享该技能的玩家,整个交易将失败,因为由于唯一的ID约束,它无法再次添加该技能。我完全理解这一点,但我认为Doctrine ORM非常聪明,只需在联结表中创建条目并忽略已有的技能。

我是否期望过多的Doctrine,如果有的话,是否有任何服务或帮助可以让我摆脱这种情况而不需要编写一堆代码。

PlayerController执行此操作以持久保存数据:

private function persistPlayer($data){

    $player = new Player($data);  //Player __construct entity extracts + assigns data

    foreach ($data->skills as $rawSkill) {
                $skill = new Skill($rawSkill);
                $player->addSkill($skill);
            }
    }

    $this->entityManager->persist($player);

    try {

        $this->entityManager->flush();

    } catch (\Exception $e) {

        error_log($e->getMessage());

    }
    return $player;
}

我的实体注释看起来像这样(并使用bin/console make:entity命令创建:

class Player
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Skill", inversedBy="skill",cascade={"persist"})
     */
    private $skill;




public function __construct($data)
{
    $this->ability = new ArrayCollection();
    $this->setId($data->id);
}


   public function addSkill(Skill $skill): self
    {
        if (!$this->skill->contains($skill)) {
            $this->skill[] = $skill;
        }

        return $this;
    }

    //.... more code

}

我的技能实体:

/**
 * @ORM\Entity(repositoryClass="App\Repository\SkillRepository")
 */
class Skill
{
    /**
     * @var integer $id
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     */
    private $id;


    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Player", mappedBy="skill" ,cascade={"persist"})
     */
    private $skill;


    public function __construct($data)
    {
        $this->ability = new ArrayCollection();

         $this->setId($data->id);

    }

    public function setId($id)
    {
        return $this->id = $id;
    }


//...more code


}

我的联结表是使用以下语法创建的:

CREATE TABLE player_skill (player_id INTEGER NOT NULL, skill_id 
INTEGER NOT NULL, PRIMARY KEY(player_id, skill_id))

2 个答案:

答案 0 :(得分:0)

尝试以下注释:

class Player
{

...

/**
 * @ORM\ManyToMany(targetEntity="App\Entity\Skill", inversedBy="skill",cascade={"persist"})
 *
 * @ORM\JoinTable(name="player_skill")
 *
 */
private $skill;

...

}
像这样,使用关系表名称

答案 1 :(得分:0)

你可以尝试下面的表格结构吗?

CREATE TABLE `player_skill` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `user_id` int(10) unsigned NOT NULL, `role_id` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `playerSkill_skillId_idx` (`skill_id`), KEY `playerSkill_playerId_idx` (`player_id`), CONSTRAINT `playerSkill_skillId_idx` FOREIGN KEY (`skill_id`) REFERENCES `skill` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `playerSkill_playerId_idx` FOREIGN KEY (`player_id`) REFERENCES `player` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

并按

注释
class Player
{

...

/**
 * @ORM\ManyToMany(targetEntity="App\Entity\Skill", 
inversedBy="skill",cascade={"persist"})
 *
 * @ORM\JoinTable(name="player_skill")
 *
 */
private $skill;

...

}