我希望Foo
有一个可选的Bar
和Bar
来选择Foo
。
我似乎设法让它工作但我只在其中一个表上创建了一个额外的列,例如它在SQL中仅在其中一个表上创建InvitationId
然后Invitation_Id
,即使两个实体的设置方式相同,但反之亦然。
所以我想做一个较小的repro所以我可以在SO上问这个问题,但在这个过程中,虽然我刚刚复制了原始实体,删除了一些属性,但我现在有一个不同的错误,这令人担忧-deterministic。
好的,代码。
[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);
错误是:
在“Product.Data.Entities.Bar”类型上声明的导航属性“Foo”已配置了冲突的外键。
原始实体仍然存在于项目中,并且以完全相同的方式设置,除了它们具有更多属性,但它们创建时没有错误,除了一个具有无关的FK列。
所以有很多问题:
为什么我已经获得Invitation_Id
列的额外InvitationId
列?
为什么我不能重现它?
为什么现在出现错误?如果我解决了这个问题,如果他们没有相同的问题,是否可以帮助我解决原始实体。
在上面的开头句中实现目标的正确方法是什么?
与此同时,我将开始逐步将Foo
和Bar
建设成Invitation
和Expectation
,直到它变得有趣。
更新
所以我最终得到了除了名字之外的所有原始实体的精确副本。这些副本导致上面的FK冲突错误,但原件没有!!
然后我删除了原件并将副本重命名为原始名称,不更改任何属性或属性,错误消失了,我又回到了无关FK列的原始版本!
疯狂。
路
答案 0 :(得分:2)
第一件事是一对一关系,一端必须是主体,另一端是依赖关系,所以你不能在两个实体中指定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显示的解决方案,但在这种情况下,您将有两种不同的关系。
答案 1 :(得分:1)
正如我在评论中提到的,因为有两种关系,并且可以为关系的每一方都有一个导航属性,我认为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);