Как ссылаться на внешний ключ без HasForeignKey()

#entity-framework

#entity-framework

Вопрос:

Использование EF 4.0 с обновлением 4.1 для POCO / code-first.

Хорошо, итак, у меня есть модель предметной области, где type Car имеет в коллекции несколько объектов типа Part . Итак, отношение один: много.

 HasMany(v => v.Parts)
  .WithRequired()
  .HasForeignKey(v => v.CarId)
  .WillCascadeOnDelete();
  

Проблема в том, что это требует от меня добавления CarId свойства к моему Part типу. Это приводит к утечке информации ORM в мою модель домена, что плохо. Маркировка всего виртуального достаточно раздражает.

Просмотр комментария к XML-документу для HasForeignKey() метода говорит об этом:

Настраивает связь для использования свойств внешнего ключа, которые предоставляются в объектной модели. Если свойства внешнего ключа не представлены в объектной модели, тогда используйте метод Map.

Это здорово и все такое. Но это приводит к ситуации с подвохом 22, потому что, если я реорганизую свой Part тип, удаляя CarId ненужное мне свойство, и обновляю свой EF model builder, чтобы не беспокоиться о сопоставлении этого свойства. Тогда, как вы можете себе представить, это означает, что я не могу вызвать HasKey() для определения составного ключа, ala:

 HasKey(v => new { v.CarId, v.PartId });
  

HasKey() похоже, что не поддерживается определение ключей на основе лямбд, не являющихся свойствами.

Каково здесь решение?

Комментарии:

1. Я думаю, что заголовок вашего вопроса должен быть таким: «Как определить первичный ключ, не предоставляя все столбцы первичного ключа в качестве свойств в модели?» Разве это не проблема на самом деле? Убивая CarId , вы хотите удалить не только свойство FK (что легко), но и часть вашего сложного PK (что, вероятно, невозможно).

2. Вы правы. Ключевым моментом здесь является то, что я не хочу лишних «обратных ссылок» в моей модели домена. Модели домена они не нужны, и они просто становятся проблемой для синхронизации. Я удивлен, что EF, похоже, требует загрязнения моей доменной модели обратными ссылками, которые касаются исключительно СУБД.

3. Вам не нужны обратные ссылки в EF, предоставлять их необязательно. Ваша проблема в том, что у вас есть составной первичный ключ, и часть его является внешним ключом. Обычно вы могли бы избавиться от свойства внешнего ключа, но не в вашем случае, потому что оно одновременно является частью PK. И вы не можете удалить PK из класса модели. Вашим лучшим вариантом было бы создать PartId только первичный ключ, затем вы могли бы удалить CarId . Это в основном то, что предложил хазимдикенли в своем ответе.

Ответ №1:

Если вам абсолютно не нравится иметь свойства внешнего ключа в вашей модели, вы могли бы удалить соглашение об обнаружении свойств FK, чтобы избежать того, что EF автоматически помечает свойства как свойства FK …

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions
        .Remove<NavigationPropertyNameForeignKeyDiscoveryConvention>();
}
  

… и затем просто не указывайте свойство FK в своем сопоставлении:

 HasMany(v => v.Parts)
    .WithRequired()
    .WillCascadeOnDelete();
  

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

Просто идея, я не уверен, работает ли это.

Ответ №2:

Ну, а как насчет добавления нового ключевого поля в таблицу CarParts, такого как CarPartId, чтобы вам не понадобился составной ключ. (Поддержка составных ключей не так уж хороша при работе с ORM.)