实体框架 - 代码优先:使用相同类型的多个子/可选属性进行映射

时间:2011-12-21 10:28:13

标签: entity-framework entity-framework-4.1 ef-code-first

我的域名模型包含用户和地址类

public User
{
   int Id
   Address PrimaryAddress
   Address SecondaryAddress
   and some other Properties
}

两者都是可选的,但每个地址都必须有一个用户。 Codeirst Mapping看起来像

modelBuilder.Entity<User>()
   .HasOptional(u => u.PrimaryAddress)
   .WithRequired()
   .WillCascadeOnDelete(false);
modelBuilder.Entity<User>()
   .HasOptional(u => u.SecondaryAddress)
   .WithRequired()
   .WillCascadeOnDelete(false);

但这并没有产生预期的结果。我期待用户表指向地址表的两个(int,null)列。和Address表可能有一个UserId(外键,int,非null)列。 但是使用上面的代码地址的“ID”列充当PK和FK(指向用户表)。

1 个答案:

答案 0 :(得分: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中的空值被视为有效值,因此如果您对可空列具有唯一约束,则只有单个记录可以具有空值。