2013-09-10 4 views
27

У меня есть две модели:от одного до нуля или один с HasForeignKey

public class Person 
{ 
    public virtual int Id { get; set; } 
    public virtual Employee Employee { get; set; } // optional 
} 

public class Employee 
{ 
    public virtual int Id { get; set; } 
    public virtual int PersonId { get; set; } 

    public virtual Person Person {get; set; } // required 
} 

public class EmployeeConfiguration : EntityTypeConfiguration<Employee> 
{ 
    public EmployeeConfiguration() 
    { 
     Property(e=>e.PersonId) // I need this property mapped 
      .HasColumnName("person_id") 
      .HasColumnType("int"); 
    } 
} 

Я хочу, чтобы сопоставить их с помощью свободно отображение. Таблица Employee имеет столбец «person_id», который не имеет значения NULL. Я попробовал следующее:

HasRequired(e => e.Person) 
    .WithOptional(p => p.Employee) 
    .Map(m => m.MapKey("person_id")); 

Но он терпит неудачу с:

System.Data.Entity.ModelConfiguration.ModelValidationException: Один или несколько ошибок проверки были обнаружены в процессе генерации модели:

person_id: Имя: каждое имя свойства в типе должно быть уникальным. Свойство имя 'person_id' уже определено.

мне нужно PersonId собственность сама по себе, так что я в принципе хочу:

HasRequired(e => e.Person) 
    .WithOptional(p => p.Employee) 
    .HasForeignKey(e => e.PersonId); // there is no such method 

Но нет такого метода здесь HasForeignKey

+0

Не существует метода HasForeignKey, потому что для такого рода отношения HasRequired() .OoOptional() 'дополнительная сторона (' Employee') будет использовать свой первичный ключ в качестве внешнего ключа. – jjj

+1

Используя ваш случай в качестве примера, это имеет смысл, потому что нет сущностей 'Employee', у которых нет соответствующего' Person', поэтому наличие 'Employee.PersonId' и' Employee.Id' является избыточным. Если вы хотите, чтобы 'PersonId' был внешним ключом, вы можете использовать' HasKey (emp => emp.PersonId) '. – jjj

+1

Как только у вас есть мультипликаторы такого типа отношений, все разваливается. – jjj

ответ

41

Хорошо, я понял, что из - вы должны использовать WithMany (да, не очевидно), чтобы сохранить внешний ключ в каком-либо виде:

Property(e => e.PersonId).HasColumnName("person_id"); 
HasRequired(e => e.Person) 
    .WithMany() 
    .HasForeignKey(p => p.PersonId); 

Подробнее см. В статье One-to-One Foreign Key Associations. Кстати, это создаст столбец внешнего ключа сотрудника для таблицы человека, но нет другого способа иметь свойство навигации и внешний ключ отдельно.


Если вам нужен внешний ключ только для чтения, вы можете изменить PersonId свойство:

public int PersonId { get { return Person.Id; } } 

И использовать оригинал отображение

HasRequired(e => e.Person) 
    .WithOptional(p => p.Employee) 
    .Map(m => m.MapKey("person_id")); 
+0

Нет, я уже сопоставил «person_id» с Employee.PersonId – joozek

+0

Из статьи: «Как вы, возможно, заметили, обе ассоциации в свободном API-коде были настроены как много-к-одному, а не один-к-одному, как вы могли ожидать. Причина проста: Code First (и EF в целом) не поддерживает взаимно-однозначные ассоциации с одним ключом ». – SWeko

+1

Объявление 1: проблема есть, мне нужен человек.Навигатор по работе с людьми Свойство, которое это решение не предоставляет Объявление 2: хороший взлом, но он заставляет присоединиться к случаю, если мне нужен только PersonId (без целого лица) Статья в статье: я расскажу позже. – joozek

3

Там на самом деле лучший способ сделать это :

HasKey(e => e.PersonId); 

HasRequired(e => e.Person) 
    .WithOptional(p => p.Employee); 

Обратите внимание, что вам больше не нужно свойство Employee.Id с таким подходом, поскольку оно было излишним с точки зрения отношения 1 к 0 или 1 в первую очередь.

+0

Спасибо за ваш ответ! Я не помню ясных обстоятельств моего вопроса (это было несколько лет назад), но я уверен, что не смог удалить «Employee.Id», потому что я работал с устаревшим db, которым я не владею – joozek

Смежные вопросы