Второе отношение Себя к Себе в Entity Framework - PullRequest
4 голосов
/ 20 января 2012

Предположим, у нас есть класс домена

public class Incident
{
    [Key]
    public virtual int IncidentId { get; set; }

    [Display(Name = "Parent Incident")]
    public virtual Incident ParentIncident { get; set; }

    [Display(Name = "Related Claim")]
    public virtual Incident ClaimIncident { get; set; }

 }

Другие свойства для простоты опущены.

Когда у меня было только ParentIncident, все работало нормально.Теперь я добавил ClaimIncident в класс.Я пытаюсь обновить свою базу данных, используя опцию Entity Framework 4.3 (PreRelease) Migrations, но получаю ошибку, что EF не знает, как сопоставить инцидент с инцидентом.

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

1 Ответ

3 голосов
/ 14 марта 2012

Это то, что я думаю, происходит.Когда у вас только ParentIncident Code First отображал это по соглашению как один конец независимой однонаправленной независимой ассоциации «один ко многим».Там много жаргона - позвольте мне объяснить:

  • Самостоятельная ссылка: как это очевидно из вопроса, Индикативная сущность находится на обоих концах отношения.
  • One-to-мани: у каждого индикатора есть один ParentIncident, и инцидент может быть родительским для многих инцидентов.
  • Однонаправленный: существует свойство навигации от инцидента к его родителю (ParentIncident), но нет свойств навигации обратной коллекции дочернего элементаинциденты.
  • Независимая ассоциация: поскольку в классе отсутствует свойство внешнего ключа, EF создает в базе данных столбец FK (называемый ParentIncident_IncidentId), но он не сопоставляется ни с каким свойством объекта.

Теперь, когда вы добавляете свойство ClaimIncident, это меняет способ, которым Code First пытается отобразить.Теперь он создает самосвязывающуюся двунаправленную ассоциацию FK «один-к-одному»:

  • «Один-к-одному», потому что он видит два свойства навигации от Инцидента к Инциденту и предполагает, что это две стороны одной и той же стороны.отношения.Поскольку ни одно из них не является свойством коллекции, отношение является взаимно-однозначным.
  • Снова двунаправленным, поскольку теперь на каждом конце отношения имеется свойство nvaigation.
  • FK, поскольку однозначноеодно отношение становится PK к PK, и EF всегда рассматривает это как отношение FK, поскольку FK (который является PK) отображается.

Но Code First не может выяснить, какая сторона этогоОтношения «один к одному» должны быть главной целью, и которая должна быть зависимой целью.И иногда это имеет значение ... так что сначала бросается Code First.

Хорошо, так что я собираюсь сделать вывод из потока и вашей модели, что вы действительно не хотите, чтобы отношения один-к-одному здесь.(Относящиеся к самому себе отношения «один к одному» между ПК и ПК вроде бы бессмысленны, поэтому вы можете утверждать, что Code First не должен его создавать, но Code First не настолько умен.)

Итак, выположить FKs. Две вещи случаются.Во-первых, Code First теперь предполагает, что это снова должны быть отношения «один ко многим».Во-вторых, Code First теперь имеет имя для свойства FK и, в свою очередь, использует это имя для именования столбца FK в базе данных.Но это имя не совпадает с именем столбца FK, уже созданного для независимого связанного, - это не ParentIncident_IncidentId.Это означает, что миграция должна будет удалить этот столбец и создать новый ... что приведет к потере данных.

Чтобы сообщить Code First, что вам действительно нужны два самоссылающихся, однонаправленных, один-ко-многим, независимые ассоциации, используйте это беглое отображение:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Incident>()
        .HasOptional(e => e.ParentIncident)
        .WithMany();

    modelBuilder.Entity<Incident>()
        .HasOptional(e => e.ClaimIncident)
        .WithMany();
}

Теперь Миграции должны корректно обновить вашу базу данных.Теперь следует сказать, что вы можете рассмотреть возможность перехода на ассоциации FK, и в этом случае вам нужно либо выполнить какое-то перемещение данных в процессе миграции, либо просто принять потерю данных, если таковые имеются, либо сказать Code First о том, чтобы продолжать использовать FKИмя столбца, который был сгенерирован ранее.

...