Учение о взаимоотношениях «один ко многим» и «один к одному» - PullRequest
2 голосов
/ 02 июля 2010

У меня есть два объекта: File и FileDetail. Файл может иметь много FileDetails, но FileDetail может иметь только один файл. Я могу заставить это работать, но я не могу ничего удалить из базы данных из-за ключевых ограничений (я не могу удалить строку File, потому что от нее зависит FileDetail, и наоборот). У меня есть следующий yaml:

File:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    ...
    fileDetail_id: integer
  relations:
    ...
    FileDetail:
      local: fileDetail_id
      foreign: id
      cascade: [delete]

FileDetail:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    file_id: integer
    ...
  relations:
    ...
    File:
      local: file_id
      foreign: id
      foreignAlias: Revisions
      cascade: [delete]

В идеале, я бы хотел, чтобы при удалении строки файла удалялись все дочерние элементы FileDetails. Было бы даже неплохо, если бы я мог просто вручную удалить все строки FileDetail и затем строку File, но из-за ключевых ограничений я не могу:

1451 - Cannot delete or update a parent row: a foreign key constraint fails (`file`, CONSTRAINT `file_filedetail_id_file_detail_id` FOREIGN KEY (`filedetail_id`) REFERENCES `file_detail` (`id`))

Как бы мне заставить этот тип отношений работать (один-ко-многим с одной стороны, но один-к-другому с другой). Или я должен просто рассматривать это как «многие ко многим» с обеих сторон?

Ответы [ 3 ]

5 голосов
/ 02 июля 2010

С Doctrine часто может быть лучше определить отношения только на одной стороне (обычно на стороне владельца) и позволить Doctrine решить остальную часть. Здесь у вас есть каскадное удаление, которое, похоже, идет в обе стороны. Попробуйте изменить схему на:

File:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    ...
  relations:
    ...
    Revisions:
      class: FileDetail
      local: id
      foreign: file_id
      type: many
      cascade: [delete]

FileDetail:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    file_id: integer

и оставьте cascade только на стороне файла. Таким образом, когда вы удаляете файл, связанные с ним записи FileDetail также будут удалены. Я также изменил псевдоним на Revisions в соответствии с вашей исходной схемой, так что вы сможете сделать:

$file->Revisions->{some FileDetail field here}

что я думаю, что вы были после. Я удалил поле filedetail_id из вашей записи File, так как если у вас может быть много записей FileDetail на файл, ваша запись File не сможет хранить все идентификаторы этих записей в одном целочисленном поле.

И, наконец, я добавил type: many к стороне владельца, поэтому Doctrine знает, что это отношение один-ко-многим со стороны Файла.

1 голос
/ 05 сентября 2012

Небольшое дополнение к ответу richsage:

В случае, если вы определяете отношение на стороне, не являющейся владельцем, у Doctrine могут возникнуть проблемы с обнаружением этой настройки.

Очевидным симптомом этого является появление сообщения об ошибке, в котором говорится, что столбец внешнего ключа не найден в ссылочной таблице.В этих случаях вы можете помочь Doctrine, предоставив атрибут "owningSide" в отношении.Взяв приведенный выше пример за основу:

File:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    ...
  relations:
    ...
    Revisions:
      class: FileDetail
      local: id
      foreign: file_id
      type: many
      owningSide: false
      cascade: [delete]
0 голосов
/ 13 января 2011

@ richsage единственная проблема, с которой я столкнулся при вашем решении, заключается в том, что для меня в определении FileDetail: file_id: должен иметь primary: true.

...