在Entity Framework 4.1 Code First中创建双向一对一关系

11

我想使用EF Code First创建两个实体之间的双向一对一关系。但是以下代码让我遇到了麻烦。你认为我应该怎么做?

public class User
{
    public string ID { get; set; }
    public string LastName { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }

    public int ProfileID { get; set; }
    public Profile Profile { get; set; }

}
public class Profile
{
    public int UserID { get; set; }
    public User User { get; set; }
    public int ProfileID { get; set; }
    public string ProfileName { get; set; }

    public DateTime CreateDate { get; set; }
    public DateTime LastUpdateDate { get; set; }

}

我希望在两个实体中都有导航属性和外键。

这会导致错误。在Fluent Mapping API中该怎么做才能使其正常工作?

1个回答

18

使用这个:

public class User
{
    public string ID { get; set; }
    public string LastName { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    public Profile Profile { get; set; }
}

public class Profile
{
    [Key, ForeignKey("User")]
    public int ProfileID { get; set; }
    public string ProfileName { get; set; }
    public DateTime CreateDate { get; set; }
    public DateTime LastUpdateDate { get; set; }
    public User User { get; set; }
}

这是在EF中建立一对一关系的唯一有效方法-从属实体的主键必须也是指向主实体的外键。EF中没有双向一对一关系,因为它无法工作。

人们有时通过两个一对多关系来克服这个问题,其中主实体没有从属实体的导航集合,并在数据库中手动定义唯一键。这需要进行手动映射:

public class User
{
    public string ID { get; set; }
    public string LastName { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    // one side MUST be nullable otherwise you have bidirectional constraint where each
    // entity demands other side to be inserted first = not possible
    public int? ProfileId { get; set; } 
    public Profile Profile { get; set; }
}

public class Profile
{
    public int ProfileID { get; set; }
    public string ProfileName { get; set; }
    public DateTime CreateDate { get; set; }
    public DateTime LastUpdateDate { get; set; }
    public int UserId { get; set; }
    public User User { get; set; }
}

在映射中,你需要定义:

modelBuilder.Entity<User>
            .HasOptional(u => u.Profile)
            .WithMany()
            .HasForeignKey(u => u.ProfileId);
modelBuilder.Entity<Profile>
            .HasRequired(u => u.User)
            .WithMany()
            .HasForeignKey(u => u.UserId);

现在你必须在数据库中定义唯一键 - 如果你正在使用 Code First,请使用自定义数据库初始化。请注意,双向一对一的概念仍然是错误的,因为两侧都要求具有唯一 FK,其中 NULL 仍包括在唯一值中,所以一旦在插入 User 前插入了 Profile,则任何没有 Profile 的其他 User 都不应存在。这可能会导致可串行化事务。


Ladislav,现在它变得非常清晰了...我明白了关系是如何建立的...虽然我同意应该有更好的支持方式来手动创建唯一键... - Preetham Reddy
为什么在一对一关系中要使用 WithMany? - angel
1
@angel:这是一个解决EF限制的变通方法——答案的第二部分是通过欺骗EF告诉它存在两个一对多关系而不是直接映射一对一来实现的。在外键列上放置唯一键约束可以在数据库级别上确保一对一关系。 - Ladislav Mrnka
@LadislavMrnka 关于在用户表中更新外键,您怎么看?这可行吗?我的意思是更改用户的配置文件(尽管在此示例中没有意义,在其他示例中有意义)。 - ninbit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接