Доктрине ORM не удалось сохранить одну сторону ManyToMany (SQLSTATE [23000]: УНИКАЛЬНОЕ нарушение ограничения) - PullRequest
0 голосов
/ 25 мая 2018

Я новичок в Symfony 4 и Doctrine, так что, возможно, я слишком многого ожидаю от Domrine ORM, но тот факт, что я не могу найти подходящую документацию, чтобы сообщить мне в любом случае, сводит меня с ума!

Ошибка

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

Сводка Я создал отношения ManyToMany между моим игроком и сущностями навыков.Каждый из этих объектов имеет свой идентификатор, установленный вручную, потому что они поступают из внешнего API.Я собираю данные в PlayerController, который очищает сторонний API для локального кэширования данных в моей БД.

Код, который я написал, позволяет сохранять (кэшировать) сторонние данные в моей базе данных.если умение, которое я добавляю, еще не было добавлено в базу данных.Однако, если я пытаюсь добавить другого игрока, который делится этим навыком, вся транзакция завершится неудачей, потому что он не сможет добавить навык снова из-за ограничения уникального идентификатора.Я полностью понимаю это, но я думал, что 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;
}

Мои аннотации Entities выглядят так (и были созданы с использованиемкоманда 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

}

И мой объект Skill:

/**
 * @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 голосов
/ 31 мая 2018

вы можете попробовать следующую структуру таблицы?

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;

...

}
0 голосов
/ 25 мая 2018

Попробуй ниже аннотацию:

class Player
{

...

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

...

}

вот так, с именем таблицы отношений

...