Я пишу модели Entity Framework Code-First без существующей базы данных. В своих объектах я объявил свои внешние отношения один-ко-многим как явно, так и как свойства навигации с отложенной загрузкой, например:

UserRecord класс

[Key]
public long ID { get; set; }

public virtual List<WorkItemRecord> WorkItemsAuthored { get; set; } // authored work items

WorkItemRecord класс:

[Key]
public long ID { get; set; }

public long AuthorID { get; set; } // user ID of the author
public virtual UserRecord Author { get; set; } // navigation lazy-loaded property

Идея сохранения внешнего ключа как идентификатора, так и свойства навигации в классе WorkItemRecord заключается в том, что в тех случаях, когда мне просто нужен фактический идентификатор пользователя, лежащий в основе, я могу ссылаться на него напрямую, не вызывая свойство и не вызывая другого Поиск в БД.

Проблема в том, что когда EF создает схему базы данных, она не связывает их вместе. Он создает отдельные столбцы: AuthorID и UserRecord_ID

Сначала я подумал, может быть, это потому, что моя собственность была Author, а не User. Однако даже когда я явно указал это с помощью атрибута свойства ...

[ForeignKey("Author")]
public long AuthorID { get; set; }
public virtual UserRecord Author { get; set; }

... У меня все еще остаются те же два столбца в сгенерированной схеме.

Также попытался поставить декоратор на другое свойство ...

public long AuthorID { get; set; }
[ForeignKey("AuthorID")]
public virtual UserRecord Author { get; set; }

... и получить тот же результат.

Я бы хотел избежать Fluent API, если это возможно, но я открыт для этого, если у меня не будет других решений.

Любые идеи?

Благодарность!

ОБНОВЛЕНИЕ

Спасибо за помощь! Fluent API работал нормально, но исправить аннотацию данных с помощью декоратора обратных свойств оказалось намного проще. Окончательное решение:

UserRecord класс:

public long ID { get; set; }
public virtual List<WorkItemRecord> WorkItemsAuthored { get; set; }

WorkItemRecord класс:

public long ID { get; set; }

[ForeignKey("Author")]
public long AuthorUserID { get; set; }

[InverseProperty("WorkItemsAuthored")]
public virtual UserRecord Author { get; set; }

У Microsoft также есть статья, посвященная этой конкретной проблеме:

https://msdn.microsoft.com/en-us/data/jj591583.aspx#Relationships

0
watkinsmatthewp 26 Апр 2016 в 23:16

2 ответа

Лучший ответ

Ссылочного свойства должно быть достаточно, чтобы EF распознал отношение «один ко многим», но есть ли у вас свойство навигации в классе UserRecord?

public class UserRecord
{
    /* other properties */
    public virtual List<WorkItemRecord> WorkItemsAuthored { get; set; }
}

Возможно, есть небольшая деталь, из-за которой EF не распознает внешний ключ.

ОБНОВЛЕНИЕ: Попробуйте InverseProperty в классе UserRecord, как показано ниже:

[InverseProperty("WorkItemsAuthored")]
public virtual UserRecord Author { get; set; } // navigation lazy-loaded property

Из «Programming Entity Framework: Code First», написанного Джулией Лерман и Роуэном Миллером:

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

Я предполагаю, что класс UserRecord имеет более одного List<WorkItemRecord>.

1
Gabor 27 Апр 2016 в 22:52

В вашем классе DbContext добавьте это в свой метод OnModelCreating.

modelBuilder.Entity<Book>() //Guessing at your class name
    .HasRequired(e => e.Author)
    .WithMany(e => e.Books)
    .HasForeignKey(e => e.AuthorID);

Это усилит ограничение.

2
Matt Rowland 26 Апр 2016 в 20:25