Entity framework EF CF-如何建立可选关系:可选关系?
我希望Entity framework EF CF-如何建立可选关系:可选关系?,entity-framework,ef-code-first,Entity Framework,Ef Code First,我希望Foo有一个可选的Bar和Bar有一个可选的Foo 我似乎设法让它工作,但我只在其中一个表上创建了一个额外的列,例如,它在SQL中只在其中一个表上创建了InvitationId,然后也在其中一个表上创建了InvitationId,尽管两个实体的设置方式相同,但设置方式相反 所以我想做一个更小的复制,这样我就可以问这个问题了,但是在这个过程中,虽然我刚刚复制了原始的实体,删除了一些属性,但我现在有一个不同的错误,令人担忧的是它是不确定的 好的,代码 [Table("Foo")] publi
Foo
有一个可选的Bar
和Bar
有一个可选的Foo
我似乎设法让它工作,但我只在其中一个表上创建了一个额外的列,例如,它在SQL中只在其中一个表上创建了InvitationId
,然后也在其中一个表上创建了InvitationId
,尽管两个实体的设置方式相同,但设置方式相反
所以我想做一个更小的复制,这样我就可以问这个问题了,但是在这个过程中,虽然我刚刚复制了原始的实体,删除了一些属性,但我现在有一个不同的错误,令人担忧的是它是不确定的
好的,代码
[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; }
}
在建模创建中的
modelBuilder.Entity<Foo>()
.HasOptional<Bar>(foo => foo.Bar)
.WithOptionalPrincipal(bar => bar.Foo);
modelBuilder.Entity()
.has可选(foo=>foo.Bar)
.WithOptionalPrincipal(bar=>bar.Foo);
错误是:
在类型“Product.Data.Entities.Bar”上声明的导航属性“Foo”已配置有冲突的外键
原始图元仍存在于项目中,并且以完全相同的方式设置,只是它们具有更多属性,但创建时不会出错,只是其中一个具有无关的FK列
所以有很多问题:
- 为什么我得到了额外的
InvitationId
列,而它已经有了InvitationId
- 为什么我不能复制它
- 为什么现在会出现错误?如果我解决了这个问题,如果我的原始实体没有相同的问题,它会帮助我处理它们吗
- 在我上面的开场白中,实现目标的正确方式是什么
同时,我将开始一点一点地将Foo
和Bar
构建回Invitation
和Expectation
直到它变得有趣
更新
所以我最终得到了除了名字以外的所有原始实体的精确副本。这些副本导致了上述FK冲突错误,但原件没有
然后我删除了原件,并将副本重命名为其原始名称,没有更改任何属性或属性,错误消失了,我回到了无关FK专栏的原始版本
疯子
Luke正如我在评论中提到的,因为有两种关系,并且可能在关系的每一方都有一个导航属性,我认为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);
modelBuilder.Entity().has可选(f=>f.Bar)
.有很多
.HasForeignKey(f=>f.BarId);
modelBuilder.Entity().has可选(b=>b.Foo)
.有很多
.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,这样您就有了一个额外的邀请Id
列
要解决您的问题,您的模型应采用这种方式(删除FK属性):
并使用相同的Fluent Api配置:
modelBuilder.Entity<Foo>()
.HasOptional(foo => foo.Bar)
.WithOptionalPrincipal(bar => bar.Foo);
modelBuilder.Entity()
.has可选(foo=>foo.Bar)
.WithOptionalPrincipal(bar=>bar.Foo);
关于为什么在您的真实代码中没有发生异常,我认为与@user2697817一样,您应该创建两种不同的关系,但我完全可以确保,因为我没有看到您的真实模型
第二个选项可能是@user2697817显示的解决方案,但在这种情况下,您将拥有两个不同的关系。我认为您的问题是,两个表之间有两个关系,只有一个导航属性。在fluent API中,您说Bar
上的Foo
属性是一种关系的一部分,但随后您将其与数据注释相结合,并说它是另一种关系的一部分。如果这有意义的话?顺便说一句,我有一个关于非确定性奇怪性的理论。一旦我更改了实体的名称,错误就消失了,出现了额外的列问题,因此我猜测这些名称改变了EF schema ThingMy系统枚举和应用其逻辑的顺序。我认为目的是创建两个关系,因此每个实体上都有外键。我认为OP需要澄清,我们都给出了两种不同的解决方案。谢谢你的回答。我讨厌这种主要和依赖的想法。我有两个实体,Foo
可能有Bar
,Bar
可能有Foo
。就数据而言,Foo
可以为null或Bar
中的行ID,Bar
可以为null或Foo
中的行ID。简单?EF不能做到这一点吗?好吧,你所描述的与@user2697817所展示的解决方案非常吻合,这是模拟一对一关系的好方法,你将在两个实体中(以及在表上)都有FK属性@Octaviccl现在我在这条路上走得更远这个项目,你实际上是对的。虽然勾选的问题对于OP来说是正确的,正如你所怀疑的那样,我试图做的不是“正确的”。谢谢,我现在已经实现了上面的功能。谢谢。这一个的问题是它有许多
。我希望Foo
有一个或零个Bar
,反之亦然@
modelBuilder.Entity<Foo>()
.HasOptional(foo => foo.Bar)
.WithOptionalPrincipal(bar => bar.Foo);