Доктрина "многие ко многим" хочет создать таблицу дважды, когда я создаю миграцию

Прежде чем я опишу свою проблему, возможно, это станет более ясным, если я начну с ошибки, которую я получаю:

$ ./app/console doc:mig:diff

  [Doctrine\DBAL\Schema\SchemaException]                 
  The table with name 'user_media_area' already exists.  

Это абсолютно верно - user_media_area существует. Я создал его в предыдущей миграции, и я не понимаю, почему Symfony пытается снова создать таблицу.

Моя проблема имеет какое-то отношение к отношениям "многие ко многим". У меня есть таблица под названием user, таблица под названием media_area и таблица под названием user_media_area.

Здесь код, где я рассказываю user о media_area (Entity/User.php):

/**
 * @ORM\ManyToMany(targetEntity="MediaArea", inversedBy="mediaAreas")
 * @JoinTable(name="user_media_area",
 *      joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@JoinColumn(name="media_area_id", referencedColumnName="id")}
 *      )
 */
private $mediaAreas;

И здесь, где я рассказываю media_area о user (Entity/MediaArea.php):

/** 
 * @ORM\ManyToMany(targetEntity="User", mappedBy="users")
 */
private $users;

Интересно, что если я удалю этот JoinTable материал из Entity/User.php, ./app/console doctrine:migrations:diff снова будет работать:

/**
 * @ORM\ManyToMany(targetEntity="MediaArea", inversedBy="mediaAreas")
 */
private $mediaAreas;

Однако это немного не так: теперь он хочет создать новую таблицу под названием mediaarea, которую я не хочу. Моя таблица уже существует и называется media_area.

Таким образом, это похоже на любой способ, Symfony пытается создать таблицу на основе этой ManyToMany вещи в моем классе user, и единственная причина, по которой проблема уходит, когда я удаляю JoinTable, - это то, что имя таблицы, которую он хочет создать (mediaarea) больше не совпадает с фактическим именем моей таблицы (media_area).

Итак, мой вопрос: Почему он вообще хочет создать новую таблицу? Что я делаю неправильно?

(Я знаю, что мои соглашения об именах отключены. Примеры базы данных Symfony и Doctrine разочаровывают многопользовательскими именами столбцов, поэтому я не всегда знаю, должен ли я делать media_area или mediaarea.)

Ответ 1

В соответствии с описанием Сопоставление ассоциации в официальных документах определения @JoinColumn и @JoinTable обычно являются необязательными и имеют разумные значения по умолчанию значения:

name: "<fieldname>_id"
referencedColumnName: "id"

Из этого можно заключить, что между двумя реализованными вами реализациями действительно нет конкретной разницы.

Однако, когда дело доходит до миграции, создание таблицы является довольно распространенным и ожидаемым поведением. Дело в том, что таблица всегда должна быть удалена и создана снова, что не происходит.

О проблеме с именем таблицы, поведение по умолчанию Doctrine 2 по умолчанию:

/**
 * @ORM\ManyToMany(targetEntity="MediaArea", inversedBy="mediaAreas")
 */
private $mediaAreas;

Попробуйте создать таблицу с именем mediaarea. Опять же, совершенно нормально.

Если вы хотите объявить конкретное имя для таблицы сущности, вы должны сделать это:

/**
 * @ORM\Table(name="my_table")
 */
class Something

Я не уверен, что это вообще поможет, но я думаю, это поместит вас, по крайней мере, на правильный путь.