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.Member1
和Relationship.Member2
中的其他两个关系无关,这两个关系也都具有未在Member
中公开的端点。
我猜,这不是你想要的。您需要在两个实体中始终有对 个端点来创建关联。一个端点始终是导航属性。第二个端点也可以是导航属性,但不是必须的,你可以省略第二个导航属性。
现在,不可能将两个导航属性(Member1
和Member2
)与一个导航属性(Relationships
)关联到一个实体中) 在另一个实体中。这显然是你想要做的。
我假设您的 Member.Relationships
属性应该表示该成员在关系中是 Member1
或 Member2
,或者它参与关系,否问题 如果是Member1
或Member2
。
很遗憾,您无法在模型中恰当地表达这一点。您必须引入RelationsshipsAsMember1
和RelationsshipsAsMember2
之类的内容,对于这两个集合,您可以使用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
列将消失,您将只获得两个预期的外键列 Member1ID
、Member2ID
,因为现在您只有两个关联,而不再是三个。
您还可以考虑是否需要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 代码优先关系表的主要内容,如果未能解决你的问题,请参考以下文章
使用实体框架 4.1 代码优先方法将一对一的表关系映射到单个实体
MVC3 代码优先 - EF4.1 不会自动创建表(使用 MySQL 和 Connector/Net 6.3.6。)
EF 4.1,代码优先:不属于“timestamp”或“rowversion”类型的属性不支持存储生成的模式“Computed”