多对多关系EF

时间:2012-04-27 19:21:49

标签: entity-framework code-first

我有两个实体对象:

   public class Contact
    {
        public int ContactID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }

        public ICollection<Friend> Friends { get; set; }

    }

和朋友:

public class Friend
{
    [Key, Column(Order = 1)]
    public int ContactId1 { get; set; }
    [Key, Column(Order = 1)]
    public int ContactId2 { get; set; }
    public DateTime DateCreated { get; set; }
}

其中ContactId1映射回ContactID,ContactId2映射回另一个ContactId。

如何确保以适当的关系生成?

2 个答案:

答案 0 :(得分:2)

您需要扩展Friend课程:

public class Friend
{
    [Key, Column(Order = 0), ForeignKey("Contact1")]
    public int ContactId1 { get; set; }
    public Contact Contact1 { get; set; }

    [Key, Column(Order = 1), ForeignKey("Contact2")]
    public int ContactId2 { get; set; }
    public Contact Contact2 { get; set; }

    public DateTime DateCreated { get; set; }
}

并在Friends中为Contact集合添加属性:

[InverseProperty("Contact1")]
public ICollection<Friend> Friends { get; set; }

(您也可以使用Fluent API代替注释。)

结果是两个一对多关系(您无法将此模型映射为多对多关系)。第一个是Contact.FriendsFriend.Contact1之间,第二个是Friend.Contact2作为一个端点。 Friend中的端点未在模型中公开。

然后,您可以查询今天之前创建的给定联系人的所有朋友联系人:

DateTime today = DateTime.Now.Date;
IEnumerable<Contact> friendContacts = context.Contacts
    .Where(c => c.ContactId == givenId)
    .Select(c => c.Friends
        .Where(f => f.DateCreated < today)
        .Select(f => f.Contact2))
    .SingleOrDefault();

<强> EIT

上述映射不起作用,因为FriendContact有两个必需的关系。默认情况下,对于所需的一对多关系,EF将启用级联删除,这对于两个关系不允许同时进行。我们需要使用Fluent API重写映射以禁用级联删除,因为数据注释无法实现这一点:

public class Contact
{
    public int ContactID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }

    public ICollection<Friend> Friends { get; set; }
}

public class Friend
{
    public int ContactID1 { get; set; }
    public Contact Contact1 { get; set; }

    public int ContactID2 { get; set; }
    public Contact Contact2 { get; set; }

    public DateTime DateCreated { get; set; }
}

然后在派生的上下文中覆盖OnModelCreating

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Friend>()
        .HasKey(f => new { f.ContactID1, f.ContactID2 });

    modelBuilder.Entity<Friend>()
        .HasRequired(f => f.Contact1)
        .WithMany(c => c.Friends)
        .HasForeignKey(f => f.ContactID1);

    modelBuilder.Entity<Friend>()
        .HasRequired(f => f.Contact2)
        .WithMany()
        .HasForeignKey(f => f.ContactID2)
        .WillCascadeOnDelete(false);  // <- Important
}

答案 1 :(得分:0)

我想你想要两行朋友在联系上引用两个,对吧?如果是,您需要两个创建朋友的实例。默认情况下,实体框架代码首先识别 通过您的财产名称的关键关系。因此,在您的朋友类中,属性应该是 名称ContactId,因为该实体是名称Contact。

public class Contact
{
    public int ContactID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }

    public ICollection<Friend> Friends { get; set; }

}

public class Friend
{
    public int ContactId { get; set; }
    public DateTime DateCreated { get; set; }
}

修改

如果你想要一个朋友有很多联系人,你需要一个关系表。

public class Contact
{
    public int ContactID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }

    public ICollection<Friend> Friends { get; set; }

}

public class Friend
{
    public int FriendId { get; set; }
    public DateTime DateCreated { get; set; }
}

public class FriendContactRel 
{
    [Key, Column(Order = 0)]
    public int ContactID { get; set; }
    [Key, Column(Order = 1)]
    public int FriendId { get; set; }
}