实体框架 - 代码优先:使用相同类型的多个子/可选属性进行映射
Posted
技术标签:
【中文标题】实体框架 - 代码优先:使用相同类型的多个子/可选属性进行映射【英文标题】:Entity Framework - Code First : Mapping with Mutliple child/optional properties of same type 【发布时间】:2011-12-21 10:28:13 【问题描述】:我的域模型有用户和地址类
public User
int Id
Address PrimaryAddress
Address SecondaryAddress
and some other Properties
两者都是可选的,但每个地址都必须有一个用户。 Codeirst 映射看起来像
modelBuilder.Entity<User>()
.HasOptional(u => u.PrimaryAddress)
.WithRequired()
.WillCascadeOnDelete(false);
modelBuilder.Entity<User>()
.HasOptional(u => u.SecondaryAddress)
.WithRequired()
.WillCascadeOnDelete(false);
但这并没有产生预期的结果。我期待用户表的两个(int,null)列指向地址表。并且地址表可能有一个 UserId(外键,int,not null)列。 但是用上面的代码地址的“ID”列作为PK和FK(指向用户表)。
【问题讨论】:
【参考方案1】:您已经映射了一对一的关系,这正是您在数据库中看到的。简而言之,您想要实现的目标是无法通过这种方式实现的。
尤其是Address
必须有User
的部分无法工作,因为User
实体上有两个导航属性,这将导致Address
表中有两个不同的FK 列,否则它们必须可以为空对于某些用户,每个地址都必须是主要地址和次要地址。
正确的模型使用默认映射进行映射(不需要流畅的映射),因为它创建的用户有两个 FK 要寻址。地址与用户存在两个一对多的关系,因为理论上您可以拥有多个具有相同地址的用户。
另一个选项是将关系建模为多对多,其中连接表将被建模为具有附加属性 AddressType
的实体。
如果你真的想遵循你当前的模型,你必须使用这个:
modelBuilder.Entity<User>()
.HasOptional(u => u.PrimaryAddress)
.WithOptionalPrincipal()
.WillCascadeOnDelete(false);
modelBuilder.Entity<User>()
.HasOptional(u => u.SecondaryAddress)
.WithOptionalPrincipal()
.WillCascadeOnDelete(false);
它将在Address
表中创建两个额外的 FK 列,并且关系本身将是一对多的(一个用户可以有多个地址)。原因是强制一对一需要 FK 的唯一性,而当前的 EF 版本不支持唯一键。您可以在后处理中对 FK 列添加唯一约束(通过 custom DB initializer 或使用 EntityFramework.Migrations),但这会导致其他问题。空值在 SQL 中被视为有效值,因此如果您对可空列有唯一约束,则只有单个记录可以具有空值。
【讨论】:
以上是关于实体框架 - 代码优先:使用相同类型的多个子/可选属性进行映射的主要内容,如果未能解决你的问题,请参考以下文章
实体框架代码优先关系 - 如何定义两个对象之间的关系:两个实体之间的可选一对一