@popov654
Специалист в области веб-технологий

Ошибка сохранения Entity с cascade в Doctrine в Symfony 5 — как избежать?

У меня есть сущность Game, она содержит коллекцию игроков Player - отношение OneToMany в ORM. Есть обратная связь от игрока к игре (поле $game). Каждому игроку соответствует один объект User - отношение ManyToOne, null=false, пользователь обязателен для каждого игрока. У одного пользователя может быть несколько игроков (по каждому игроку на сыгранную игру), обратной связи пока нет, не создал, так как нет необходимости.

Стоит задача сделать возможность в момент создания игры не только создавать игроков и пользователей, но и устанавливать пользователям контактные данные. Кроме того, если пользователь с заданным e-mail уже существует, требуется привязать существующего пользователя, а не создавать нового.

Сейчас я написал некоторый код, он работает, но только в случае новых e-mail адресов. Как только я пытаюсь подставить существующего игрока, код вылетает с одной из двух ошибок:

1. Ошибка Doctrine, "a new entity was found through the relationship App\Entity\Game#player that was not configured to cascade persist operations for entity App\Entity\Player". Действительно, для списка игроков в игре не установлена опция cascade. Если же добавить её, получаю ошибку номер 2
2. SQL Error: Duplicate unique identifier N (где N - целое число, равное id уже существующего пользователя в таблице users, которого я пытаюсь подставить в поле $user для нового игрока).

Если все пользователи создаются с нуля, ошибки нет. Ошибка вылетает в тот момент, когда я вызываю persist() для объекта $game после заполнения коллекции $players в отдельном методе и создания всех пользователей. Попытки вызывать persist() для объектов пользователей и игроков внутри того метода ничего в сущности не меняют.

Общий алгоритм моего кода:

1. Получить Symfony форму на вход, в форме есть две вложенных коллекции - lectures и players. Лекции не имеют вложенных сущностей, поэтому с ними куда как проще - к тому же, их нельзя переиспользовать повторно, всегда создаются новые.
2. Создать объект класса Game - это нужно для того, чтобы получить его числовой id, который затем будет использоваться в дефолтных логинах создаваемых пользователей
3. Очистить коллекцию $players, которая заполнена автоматически (предварительно сохранив её содержимое в массив) - если этого не сделать, получим ошибку, что поле $user равно null, а это запрещено constraint-ом.
4. В цикле пройтись по массиву ролей, создать игроков, для каждой роли получить контактные данные из специального аргумента метода (эти данные тоже есть в Symfony форме, но с атрибутом mapped =>false).
5. Для каждого игрока попытаться найти пользователя по переданному e-mail адресу. Если такого нет - создать, иначе получить из метода репозитория через QueryBuilder. Установить контактные данные пользователю, установить пользователя в поле $user у игрока.
6. Выйдя из этого метода, вызвать persist и flush для игры - тут происходит ошибка.

Что я делаю не так? Возможность переиспользовать пользователей - бизнес-требование. Я могу попробовать удалять пользователя, заново его создавать и ставить прежний id - но мне не нравится такое количество лишних операций.
  • Вопрос задан
  • 63 просмотра
Решения вопроса 1
Каждому игроку соответствует один объект User - отношение OneToOne, null=false, пользователь обязателен для каждого игрока. У одного пользователя может быть несколько игроков (по каждому игроку на сыгранную игру)

Это не OneToOne, это ManyToOne.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы