EF 4.1 Code First Relationship表

时间:2011-11-06 07:21:09

标签: asp.net-mvc-3 entity-framework ef-code-first

设置

使用MVC 3 + Code First

以下是我的课程

public class Member
    {
        [Key]
        public Guid ID { get; set; }

        [Required]
        public String Email { get; set; }

        [Required]
        public String FirstName { get; set; }

        [Required]
        public String LastName { get; set; }

        public String Sex { get; set; }

        public String Password { get; set; }

        public String PasswordSalt { get; set; }

        public DateTime RegisterDate { get; set; }

        public DateTime LastOnline { get; set; }

        public String SecurityQuestion { get; set; }

        public String SecurityAnswer { get; set; }

        public virtual ICollection<FamilyMember> Families { get; set; }

        public virtual ICollection<Relationship> Relationships { get; set; }


    }


public class Relationship
    {
        [Key]
        public Guid ID { get; set; }

        [ForeignKey("Member1")]
        public Guid Member1ID { get; set; }

        [ForeignKey("Member2")]
        public Guid Member2ID { get; set; }

        public Guid RelationshipTypeID { get; set; }

        public virtual RelationshipType RelationshipType { get; set; }

        public virtual Member Member1 { get; set; }

        public virtual Member Member2 { get; set; }

    }

以下是问题

正在使用以下列创建数据库表“Relationship”:

ID,Member1ID,Member2ID,RelationshipTypeID, Member_ID

为什么要创建 Member_ID 列?

我看过this帖子,其中用户具有相同类型的设置,但我不确定如何正确定义InverseProperty。我尝试使用流畅的API调用,但我可以告诉他们在这里不会工作,因为我有两个外键引用同一个表。

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

Member_ID是EF为导航属性Member.Relationships创建的外键列。它属于Member.Relationships引用最终端点的第三个关联,该端点未在Relationship实体中公开。这种关系与Relationship.Member1Relationship.Member2中的其他两个关系无关,这两个关系也都有一个未在Member中公开的端点。

我想,这不是你想要的。您需要始终在两个实体中端点来创建关联。一个端点始终是导航属性。第二个端点 也可以是导航属性,但不是必需的,您可以省略第二个导航属性。

现在,不可能的是将两个导航属性(Member1Member2)与一个一个导航属性关联在一个实体中(Relationships)在另一个实体中。这就是你想要做的事情。

我认为您的Member.Relationships属性应该表明该成员在关系中属于Member1Member2,或者参与关系,无论如果是Member1Member2

很遗憾,你无法在模型中恰当地表达这一点。您必须引入类似RelationsshipsAsMember1RelationsshipsAsMember2的内容,对于这两个集合,您可以使用InverseProperty属性,如另一个问题所示。此外,您还可以添加一个辅助属性来连接两个集合。但这不是映射的属性,而是只读:

public class Member
{
    // ...

    [InverseProperty("Member1")]
    public virtual ICollection<Relationship> RelationshipsAsMember1 { get; set; }
    [InverseProperty("Member2")]
    public virtual ICollection<Relationship> RelationshipsAsMember2 { get; set; }

    public IEnumerable<Relationship> AllRelationships
    {
        get { return RelationshipsAsMember1.Concat(RelationshipsAsMember2); }
    }
}

访问AllRelationships将导致两次查询并往返数据库(使用延迟加载),以便在它们在内存中连接之前先加载这两个集合。

通过此映射,Member_ID列将消失,您将只获得两个预期的外键列Member1IDMember2ID,因为现在您只有两个关联而不是三个。< / p>

您还可以考虑是否需要Relationships实体中的Member集合。如上所述,双方的导航属性不是必需的。如果您很少需要从成员导航到其关系,您可以使用Relationship集上的查询来获取关系,如下所示:

var relationships = context.Relationships
    .Where(r => r.Member1ID == givenMemberID || r.Member2ID == givenMemberID)
    .ToList();

...或...

var relationships = context.Relationships
        .Where(r => r.Member1ID == givenMemberID)
    .Concat(context.Relationships
        .Where(r => r.Member2ID == givenMemberID)
    .ToList();

这将为您提供ID = givenMemberID的成员参与的所有关系,而无需Member实体上的导航集合。