Подтвердить что ты не робот

Почему EF-код генерирует посторонний столбец внешнего ключа?

Я использую сущность framework code-first, чтобы автоматически создать мою схему базы данных, и один из моих объектов выглядит следующим образом:

public class AssessmentsCaseStudies {
    #region Persisted fields
    [Required]
    [Key, Column(Order=0)]
    [ForeignKey("Assessment")]
    public int AssessmentId { get; set; }

    [Required]
    [Key, Column(Order=1)]
    [ForeignKey("CaseStudy")]
    public int CaseStudyId { get; set; }

    [Required]
    public int Score { get; set; }

    [ForeignKey("Follows")]
    public int? FollowsCaseStudyId { get; set; }
    #endregion

    #region Navigation properties
    public virtual Assessment Assessment { get; set; }
    public virtual CaseStudy CaseStudy { get; set; }
    public virtual CaseStudy Follows { get; set; }
    #endregion
}

Когда EF автоматически генерирует мою базу данных, он генерирует таблицу со следующими столбцами:

AssessmentId (PK, FK, int, not null)
CaseStudyId (PK, FK, int, not null)
Score (int, not null)
FollowsCaseStudyId (FK, int, null)
CaseStudy_CaseStudyId (FK, int, null)

Все это отлично от столбца CaseStudy_CaseStudyId. Почему это было создано? Для чего это? Как я могу остановить его создание? Мое подозрение в том, что EF больше не может автоматически сопоставлять CaseStudy ICollection<AssessmentsCaseStudies> с столбцом CaseStudyId, поэтому он создает свой собственный столбец, чтобы связать их вместе для этого свойства навигации.

4b9b3361

Ответ 1

По какой-то причине предложение предложения Slauma InverseProperty не работает. В чем заключалась работа, определяющая связь между двумя свойствами навигации CaseStudy в AssessmentsCaseStudies и объектом CaseStudy через Fluent API в моем контексте базы данных OnModelCreating:

modelBuilder.Entity<AssessmentsCaseStudies>()
    .HasRequired(acs => acs.CaseStudy)
    .WithMany(cs => cs.AssessmentsCaseStudies)
    .HasForeignKey(acs => acs.CaseStudyId)
    .WillCascadeOnDelete(false);

modelBuilder.Entity<AssessmentsCaseStudies>()
    .HasOptional(acs => acs.Follows)
    .WithMany()  // No reverse navigation property
    .HasForeignKey(acs => acs.FollowsCaseStudy)
    .WillCascadeOnDelete(false);

После добавления код миграции, сгенерированный при я Add-Migration, больше не пытается добавить столбец CaseStudy_CaseStudyId, и я просто добавлю столбец FollowsCaseStudyId с соответствующим отношением внешнего ключа.

Ответ 2

Поскольку у вас есть два навигационных свойства типа CaseStudy в вашем объекте AssessmentsCaseStudies и AssessmentsCaseStudies в вашем элементе CaseStudy EF не может решить, какая из двух CaseStudy навигация свойства, к которым относится эта коллекция. Оба варианта могут быть возможны, и оба варианта приведут к действительной, но другой модели сущности и схеме базы данных.

В такой неоднозначной ситуации соглашение EF должно создавать фактически три отношения, то есть ваша коллекция в CaseStudy не относится ни к одному из двух свойств навигации CaseStudy, но имеет третью ( но не выставлена ​​и "невидимая" конечная точка в AssessmentsCaseStudies. Это третье отношение является причиной третьего внешнего ключа, который вы видите в базе данных, - с подчеркиванием. (Подчеркивание всегда является убедительным свидетельством того, что что-то происходит по соглашению об отображении, а не по вашей явной конфигурации или аннотации данных.)

Чтобы устранить проблему и переопределить соглашение, вы можете применить атрибут [InverseProperty], указав при этом свойство навигации CaseStudy для коллекции AssessmentsCaseStudies:

[InverseProperty("AssessmentsCaseStudies")] // the collection in CaseStudy entity
public virtual CaseStudy CaseStudy { get; set; }

Вы также можете (в качестве альтернативы, вам не нужны оба) поместить атрибут на сборку:

[InverseProperty("CaseStudy")] // the CaseStudy property in AssessmentsCaseStudies entity
public virtual ICollection<AssessmentsCaseStudies> AssessmentsCaseStudies { get; set; }

Ответ 3

Для тех, кто приземляется здесь, ища решение, если вы пробовали предыдущие ответы и по-прежнему получаете дополнительный столбец внешнего ключа, найдите любые свойства, которые вы, возможно, определили ниже, по вашему классу POCO, который вы не планировали сопоставить поля БД. Даже если они содержат блоки кода, как и для сложных get accessors, Entity Framework попытается сопоставить их с базой данных. Это может привести к дополнительным столбцам внешнего ключа, если ваши свойства возвращают объекты. Чтобы быть в безопасности, либо украсьте такие свойства атрибутом [NotMapped], либо преобразуйте их в методы.