首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Doctrine无法持久化ManyToMany的一侧(SQLSTATE[23000]:唯一约束冲突)

Doctrine无法持久化ManyToMany的一侧(SQLSTATE[23000]:唯一约束冲突)
EN

Stack Overflow用户
提问于 2018-05-25 05:31:25
回答 2查看 252关注 0票数 0

我是Symfony 4和Doctrine的新手,所以也许我对Doctrine ORM的期望太高了,但是我找不到合适的文档来告诉我,这两种方式都让我抓狂!

错误

代码语言:javascript
复制
SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: skill.id

总结我已经在我的玩家和技能实体之间创建了一个ManyToMany关系。这些实体中的每一个都有自己的ID手动设置,因为它们来自外部API。我正在构建PlayerController中的数据,它抓取第三方应用程序接口以在我的数据库中本地缓存数据。

如果我添加的技能还没有添加到数据库中,那么我编写的代码允许在我的数据库中存储(缓存)第三方数据。但是,如果我尝试添加另一个共享该技能的玩家,整个事务将失败,因为由于唯一id约束,它不能再次添加该技能。我完全明白这一点,但我认为Doctrine ORM足够聪明,可以简单地在连接表中创建条目,而忽略已经存在的技能。

我对Doctrine的期望是不是太高了?如果是这样的话,有没有什么服务或帮助器可以让我在不写一堆代码的情况下摆脱这种情况?

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

代码语言:javascript
复制
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命令创建的:

代码语言:javascript
复制
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

}

和我的技能实体:

代码语言:javascript
复制
/**
 * @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


}

我的连接表是使用以下语法创建的:

代码语言:javascript
复制
CREATE TABLE player_skill (player_id INTEGER NOT NULL, skill_id 
INTEGER NOT NULL, PRIMARY KEY(player_id, skill_id))
EN

回答 2

Stack Overflow用户

发布于 2018-05-25 19:06:11

尝试下面的注释:

代码语言:javascript
复制
class Player
{

...

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

...

}

如下所示,使用关系表名

票数 -1
EN

Stack Overflow用户

发布于 2018-05-31 18:16:51

你能试试下面的表结构吗?

代码语言:javascript
复制
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;

并在注解后面加上

代码语言:javascript
复制
class Player
{

...

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

...

}
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50518445

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档