EF 4.1 代码优先关系表

Posted

技术标签:

【中文标题】EF 4.1 代码优先关系表【英文标题】:EF 4.1 Code First Relationship table 【发布时间】:2011-11-06 07:21:09 【问题描述】:

设置

使用 MVC 3 + 代码优先

这是我的课程

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; 

    

问题来了

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

ID、Member1ID、Member2ID、RelationshipTypeID、Member_ID

为什么要创建 Member_ID 列?

我看到this 帖子中用户具有相同类型的设置,但我不确定如何正确定义 InverseProperty。我尝试使用流利的 API 调用,但据我所知,它们在这里不起作用,因为我有两个外键引用同一个表。

任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

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,因为现在您只有两个关联,而不再是三个。

您还可以考虑是否需要Member 实体中的Relationships 集合。如前所述,不需要两侧的导航属性。如果您很少需要从一个成员导航到它的关系,您也可以使用 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 实体上的导航集合。

【讨论】:

你让我想得更多,我认为你甚至不需要 Member.Relationships 属性是对的。我猜从我过去的作品中,你总是有办法导航。但是如果我需要加载关系,我可以只查询关系表。这样做的一个缺点是它在我的视图模型中不容易使用。

以上是关于EF 4.1 代码优先关系表的主要内容,如果未能解决你的问题,请参考以下文章

EF 4.1 复杂关系的实体映射

使用实体框架 4.1 代码优先方法将一对一的表关系映射到单个实体

EF 4.1 代码优先和成员资格

2个表之间的关系 - 一对多和一对一(可空)EF代码优先

MVC3 代码优先 - EF4.1 不会自动创建表(使用 MySQL 和 Connector/Net 6.3.6。)

EF 4.1,代码优先:不属于“timestamp”或“rowversion”类型的属性不支持存储生成的模式“Computed”