繁体   English   中英

Entity Framework 6 FluentApi 一对一关系配置

[英]Entity Framework 6 FluentApi One-to-One Relationship configuration

[Table("Child", Schema = "dbo")]
public partial class Child
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public int Id { get; set; }

    public int? Parent1Id { get; set; }

    public int? Parent2Id { get; set; }

    public virtual Parent Parent1 {get; set}   
    public virtual Parent Parent2 {get; set}      
}

[Table("Parent", Schema = "dbo")]
public partial class Parent
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public int Id { get; set; }

    public virtual Child Child1 { get; set; }
    public virtual Child Child2 { get; set; }
  //modelBuilder below would work if I had this
  //public virtual ICollection<Child> Child1 { get; set; }

}

这意味着父子之间是一对一的关系。 Parent1Id 和 Parent2Id 可以为空。

我只找到了一对多关系的示例(使用 FluentAPI),如果我在 Parent 中有一个 Child 集合,我必须执行以下操作:

modelBuilder.Entity<Parent>()
                .HasMany(e => e.Child1)
                .WithOptional(e => e.Parent1)
                .HasForeignKey(e => e.Parent1Id);
modelBuilder.Entity<Parent>()
                .HasMany(e => e.Child2)
                .WithOptional(e => e.Parent2)
                .HasForeignKey(e => e.Parent2Id);

孩子将有 2 个 FK 参考父母。 父级没有引用子级的 FK。

我的问题是,如何使用 EF 6.x 以一对一的关系做到这一点? 我看到了 HasOne() 方法,但它来自 EFCore,所以我在这个方法中没有选择。

谢谢

注意:从技术上讲,MS SQL 服务器中的一对一关系是不可能的。 这些将始终是一对零或一的关系。 EF forms 不在数据库中的实体上的一对一关系。

https://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx

EF6 自然只支持使用所谓的共享主键关联的一对一关系,其中依赖的 PK 也用作 FK。 但是,它们不适用于这种情况(当您需要两个实体之间的多个一对一关系时)。 因此,您需要基于 FK 的一对一关系。

它们受支持,但有以下限制:

  • EF6 不会在数据库中强制执行“到 1”(或“到 0 或 1”)所需的 FK 列上创建唯一约束/索引,因此从数据库的角度来看,它们将是一对多的.
  • 不支持显式 FK 属性(请注意在配置一对一关系时缺少HasForeignKey fluent API)。 您必须删除它们并仅使用导航属性。 可以使用MapKey方法中的Map指定 FK名称。

您必须接受这些限制,否则您不能将 EF6 与此类 model 一起使用。

首先从 model 中删除显式 FK 属性:

// remove these:
//public int? Parent1Id { get; set; }
//
//public int? Parent2Id { get; set; }

接下来要考虑的是 EF 关系始终认为一方是主要的,另一方是依赖的。 在一对多中,“一”方始终是主体,“多”方始终是从属。 对于一对一,通常需要的一端是主体,可选的一端是依赖端,但是当两端都是必需的或两端都是可选的(如您的情况)时,您必须使用适当的WithRequired / WithOptional方法,其中Principal / Dependent后缀指定如何对待正在配置的实体( Has方法的泛型类型参数)。 这很重要,通常会让人感到困惑,因为 Map 内部的流利配置的Map始终适用于依赖实体,无论使用哪个实体来启动配置。

话虽如此,在您的示例中,有两种关系, Parent都是委托人, Child是受抚养人,两端都是可选的。 因此流畅的配置可以是

modelBuilder.Entity<Parent>()
    .HasOptional(p => p.Child1)
    .WithOptionalPrincipal(c => c.Parent1)
    .Map(c => c.MapKey("Parent1Id"));

modelBuilder.Entity<Parent>()
    .HasOptional(p => p.Child2)
    .WithOptionalPrincipal(c => c.Parent2)
    .Map(c => c.MapKey("Parent2Id"));

它也可以通过其他方式配置:

modelBuilder.Entity<Child>()
    .HasOptional(c => c.Parent1)
    .WithOptionalDependent(p => p.Child1)
    .Map(c => c.MapKey("Parent1Id"));

modelBuilder.Entity<Child>()
    .HasOptional(c => c.Parent2)
    .WithOptionalDependent(p => p.Child2)
    .Map(c => c.MapKey("Parent2Id"));

注意:使用一个或另一个,不要同时使用。 通常关系配置从具有导航属性的一端开始(因为它是Has方法所必需的),但是当两端都有导航时,这只是个人喜好/品味的问题。

父母是委托人,孩子是受抚养人,因此孩子需要父母,但孩子对父母来说是可选的:

modelBuilder.Entity<Child>()
    .HasRequired(c => c.Parent1)
    .WithOptional(p => p.Child1)
    .HasForeignKey(c => c.Parent1Id);

通常,您会使用受抚养人的 PK 作为主体实体的 FK(这是确保一对一关系的原因),但您在这里尝试一些不寻常的事情 - 您似乎想要一对二的关系. 我的意见是重新考虑您的设计 - 使其成为 1:N 并限制应用程序/DbContext 代码中的依赖项数量或从Child派生两种不同类型,以便它们是 DB/ERM model 中的不同实体,然后使用标准“PK作为 FK”的一对一映射。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM