EF CF - 如何建立 optional:optional 关系?

EF CF - How do I build optional:optional relationship?

我希望 Foo 有一个可选的 BarBar 有一个可选的 Foo

我似乎设法让它工作,但我只在其中一个表上创建了一个额外的列,例如它只在其中一张表上 InvitationId 然后 Invitation_Id in SQL,即使两个实体的设置方式相同,但相反。

所以我想做一个更小的复现,这样我就可以在 SO 上提问,但是在这个过程中,虽然我刚刚复制了原始实体,删除了一些属性,但我现在有一个不同的错误,这是令人担忧的不确定性。

好的,代码。

[Table("Foo")]
public partial class Foo
{
    [Key]
    public Guid Id { get; set; }

    [Required]
    [StringLength(128)]
    public string Name { get; set; }

    // Referential

    [ForeignKey("Bar")]
    public Guid? BarId { get; set; }

    public virtual Bar Bar { get; set; }
}

[Table("Bar")]
public partial class Bar
{
    [Key]
    public Guid Id { get; set; }

    [Required]
    [StringLength(128)]
    public string Name { get; set; }

    // Referential

    [ForeignKey("Foo")]
    public Guid? FooId { get; set; }

    public virtual Foo Foo { get; set; }
}

并且在OnModelCreating

    modelBuilder.Entity<Foo>()
        .HasOptional<Bar>(foo => foo.Bar)
        .WithOptionalPrincipal(bar => bar.Foo);

错误是:

The navigation property 'Foo' declared on type 'Product.Data.Entities.Bar' has been configured with conflicting foreign keys.

原始实体仍然存在于项目中,并且以完全相同的方式设置,除了它们具有更多属性,但它们的创建没有错误,除了一个具有无关的 FK 列。

所以有很多问题:

与此同时,我将开始一点一点地将 FooBar 构建回 InvitationExpectation,直到变得有趣为止。

更新

所以我最终得到了除了名称之外的所有原始实体的精确副本。这些副本导致了上面的FK冲突错误,但原件没有!

然后我删除了原件并将副本重命名为原来的名称,更改了 none 属性或属性,错误消失了,我又回到了无关 FK 列的原始问题!

疯狂。

卢克

正如我在评论中提到的那样,因为存在两种关系,并且可以为关系的每一方都有一个导航 属性 我认为 EF 无法区分哪个导航道具是哪个关系的一部分.
我建议在 OnModelCreating

中明确定义这两种关系
modelBuilder.Entity<Foo>().HasOptional(f => f.Bar)
                          .WithMany()
                          .HasForeignKey(f => f.BarId);

modelBuilder.Entity<Bar>().HasOptional(b => b.Foo)
                          .WithMany()
                          .HasForeignKey(b => b.FooId);

首先,在一对一关系中,一端必须是主体,另一端是从属,因此您不能在两个实体中指定 FK 属性。第二件事是如果你打算使用 FK 属性,EF 要求依赖实体的 PK 也应该是 FK:

public class Principal
{
   public int Id{get;set;}
   public virtual Dependent Dependent{get;set;}
}

public class Dependent
{
   [Key, ForeignKey("Principal")]
   public int PrincipalId{get;set;}

   public virtual Principal Principal{get;set;}
}

第三件事是EF让你配置一个一对一的关系,在双方使用Fluent API,但是你可以指定FK,因为正如我之前所说,它应该被配置也作为 PK,因此 EF 将在 DB 中为您处理该 FK,这样您就有了一个额外的 Invitation_Id 列。

要解决您的问题,您的模型应该是这样的(删除 FK 属性):

[Table("Foo")]
public partial class Foo
{
    [Key]
    public Guid Id { get; set; }

    [Required]
    [StringLength(128)]
    public string Name { get; set; }

    // Referential
    public virtual Bar Bar { get; set; }
}

[Table("Bar")]
public partial class Bar
{
    [Key]
    public Guid Id { get; set; }

    [Required]
    [StringLength(128)]
    public string Name { get; set; }

    // Referential
    public virtual Foo Foo { get; set; }
}

并使用相同的 Fluent Api 配置:

 modelBuilder.Entity<Foo>()
        .HasOptional(foo => foo.Bar)
        .WithOptionalPrincipal(bar => bar.Foo);

关于为什么在你的真实代码中没有发生异常,我和@user2697817 一样认为,你应该创建两个不同的关系,但我可以完全确定,因为我没有看到你的真实模型。

第二个选项可能是@user2697817 显示的解决方案,但在那种情况下,您将拥有两种不同的关系。