EF Code First中的一对一映射问题

时间:2012-10-18 16:07:09

标签: .net entity-framework

考虑这种情况:

public class House
{
    public string Name { get; set; }
    public virtual Person Person1 { get; set; }
    public virtual Person Person2 { get; set; }
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public House House { get; set; }
}

// Relationships
this.HasOptional(t => t.Person1)
    .WithRequired(t => t.House);
this.HasOptional(t => t.Person2)
    .WithRequired(t => t.House);

当我尝试插入House的实例时,抛出了一个MetaDataException:

  

指定的架构无效。错误:(36,6):错误0040:输入   House_Person1未在命名空间Company.Models(Alias = Self)中定义。

经过多次黑客攻击后,我认为这样做有效:

// Relationships
this.HasOptional(t => t.Person1)
    .WithRequired();
this.HasOptional(t => t.Person2)
    .WithRequired();

但是我不会让EF填充Person.House属性。我可以模仿这种行为(如下所示)吗?

    public virtual Person Person1
    {
        get
        {
            return _person1;
        }
        set
        {
            _person1 = value;
            _person1.Haushalt = this;
        }
    }

    public virtual Person Person2
    {
        get
        {
            return _person2;
        }
        set
        {
            _person2 = value;
            _person2.Haushalt = this;
        }
    }

1 个答案:

答案 0 :(得分:2)

您不能在两个不同的关系中使用相同的导航属性(Person.House)(House_Person1House_Person2)。

另一个限制是EF仅支持shared primary key associations作为真正的一对一关系。这意味着相关的HousePerson必须具有相同的主键值。但由此得出House.Person1House.Person2需要与House具有相同的PK值。换句话说:Person1Person2永远不会是不同的人。

我建议您将关系映射为一对多关系,并在应用程序的业务逻辑中确保House不得超过两个Person。 (因为您当前的映射允许Person1Person2是可选的,所以允许零个或仅一个人:

public class House
{
    public string Name { get; set; }
    public virtual ICollection<Person> People { get; set; }
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public House House { get; set; }
}

this.HasMany(t => t.People)
    .WithRequired(t => t.House);

修改

如果你想在Person中保留两个House导航属性,你只能将其映射为两个一对多的关系(即使这种关系在商业角度来看是错误的)而没有Person中的导航属性(如显示here):

this.HasOptional(t => t.Person1)
    .WithMany();
this.HasOptional(t => t.Person2)
    .WithMany();

您可以像在上一段代码段中一样使用House中的Person媒体资源,但需要将其从模型中排除:

modelBuilder.Entity<Person>()
    .Ignore(t => t.House);
当您从数据库加载Person.House实体时,

Person不再是导航属性,无法加载它(使用急切或延迟加载)。