实体框架:创建与自身的一对一关系

时间:2013-01-20 11:46:02

标签: entity-framework ef-code-first code-first

我有实体联系人必须链接到自己而不是分层模式

public partial class Contact 
{
  [Key, Column(Order = 0)]
  public int AgentId { get; set; }
  [Key, Column(Order = 1)]
  public int ContactId { get; set; }
  public virtual Contact Opposite { get; set; }
  public ..... many other properties
}

每个联系人都与Contact相对联ON c1.AgentId = c2.ContactId AND c1.ContactId = c2.AgentId。 相反的联系是可选的,但是当它存在时,它们是一对一的。不是亲子。 此关系的名称必须为Opposite。我已经在Contact类声明了属性。现在我正试图建立关系,但这不起作用,我觉得我不知道如何正确设置它。请指教?

public class EFDbContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        Action<ForeignKeyAssociationMappingConfiguration> mapKey = x => x.MapKey("ContactId", "AgentId");
        modelBuilder.Entity<Contact>().HasOptional<Contact>(c => c.Opposite).WithRequired().Map(mapKey);
    }
}

1 个答案:

答案 0 :(得分:2)

当您使用主键作为关系的外键时,关系不能是可选,因为主键不能具有NULL值。外键将始终具有值 - 例如(ContactId = 1,AgentId = 2) - 如果行(AgentId = 1,{{},则会违反外键约束1}} = 2)不存在。

但是对于必需的关系,您只能拥有成对的行,并且不可能将任何有意义的行插入到数据库表中,因为它总是违反外键约束:要插入行(ContactId = 1,AgentId = 2)行(ContactId = 2,AgentId = 1)必须存在,反之亦然。您可以插入的唯一可行行是(ContactId = 1,AgentId = 1),即ContactId联系人是联系人本身的行。

为了实现可选关系,您需要单独的外键:

Opposite

这是一对多的关系。使用Fluent API而不是数据注释,它将是:

public partial class Contact 
{
    [Key, Column(Order = 0)]
    public int AgentId { get; set; }
    [Key, Column(Order = 1)]
    public int ContactId { get; set; }

    [ForeignKey("Opposite"), Column(Order = 2)]
    public int? OppositeContactId { get; set; }
    [ForeignKey("Opposite"), Column(Order = 3)]
    public int? OppositeAgentId { get; set; }

    public virtual Contact Opposite { get; set; }

    //...
}

在EF方面,你无法使它成为一对一的关系。您只能在数据库中的复合外键上添加唯一索引,以确保没有两个联系人具有相同的反向。