关联的主要终点在实体框架中以1:1关系表示什么


269
public class Foo
{
    public string FooId{get;set;}
    public Boo Boo{get;set;}
}


public class Boo
{
    public string BooId{get;set;}
    public Foo Foo{get;set;}
}

当我收到错误消息时,我正在尝试在Entity Framework中执行此操作:

无法确定类型'ConsoleApplication5.Boo'和'ConsoleApplication5.Foo'之间的关联的主要终点。必须使用关系流利的API或数据注释显式配置此关联的主要端。

我已经在StackOverflow上看到了有关此错误的解决方案的问题,但我想了解术语“主要目的”的含义。


Answers:


378

在一对一关系中,一端必须是主体,第二端必须是从属关系。主体端是将首先插入的端,并且可以存在而无需从属端。从属端是必须在主体后插入的一端,因为它具有主体的外键。

如果是实体框架FK,则从属中的FK也必须是其PK,因此在您的情况下,您应该使用:

public class Boo
{
    [Key, ForeignKey("Foo")]
    public string BooId{get;set;}
    public Foo Foo{get;set;}
}

或流利的贴图

modelBuilder.Entity<Foo>()
            .HasOptional(f => f.Boo)
            .WithRequired(s => s.Foo);

6
@Ladislav,我需要制作两个独立的表,并且两个表都有一个可选的相互引用(一对一),我希望它们两个都有各自的PK,这怎么可能?我提出了一个单独的问题
Shimmy Weitzhandler 2012年

10
您不知道要花多少时间才能找到答案-ms文档是POOOOOOP ty。
gangelo 2013年

1
注意,您可能需要使用System.ComponentModel.DataAnnotations.Schema添加;在VS2012中获取ForeignKey
stuartdotnet 2013年

2
那是不是Foo就是这个委托人?
bflemi3 2013年

8
@ bflemi3您是正确Boo的依赖项,需要一个Foo,并获取外键。Foo是委托人,可以不加存在Boo
科林

182

您还可以使用[Required]数据注释属性来解决此问题:

public class Foo
{
    public string FooId { get; set; }

    public Boo Boo { get; set; }
}

public class Boo
{
    public string BooId { get; set; }

    [Required]
    public Foo Foo {get; set; }
}

Foo是必需的Boo


这对于我下面的代码是正确的,在下面的代码中,我希望两者之间有一个映射,作为一个单独的实体public class Organization {public int Id {get; 组; }}公共类用户{public int Id {get; 组; }}公共类UserGroup {[Key] public int Id {get; 组; } [必需]公共虚拟组织组织{ 组; } [必需]公共虚拟用户User {get; 组; }
AndyM 2014年

我正在使用Oracle,但没有流利的api对我有用。多谢兄弟。很简单。
CameronP 2014年

11
请注意,使用此解决方案时,尝试更新Boo从数据库中检索到的a时,将获得验证异常,除非您首先触发该Foo属性的延迟加载。entityframework.codeplex.com/SourceControl/network/forks/…– NathanAldenSr 2015
56

2
那不应该Boo Boo是虚拟的吗?
Simon_Weaver

1
@NathanAldenSr现在的链接不好,您如何进行更改?
CamHart

9

这参考了@Ladislav Mrnka关于使用流利的api配置一对一关系的答案。

存在FK of dependent must be it's PK无法进行的情况。

例如,Foo已经与拥有一对多关系Bar

public class Foo {
   public Guid FooId;
   public virtual ICollection<> Bars; 
}
public class Bar {
   //PK
   public Guid BarId;
   //FK to Foo
   public Guid FooId;
   public virtual Foo Foo;
}

现在,我们必须在Foo和Bar之间添加另一个一对一的关系。

public class Foo {
   public Guid FooId;
   public Guid PrimaryBarId;// needs to be removed(from entity),as we specify it in fluent api
   public virtual Bar PrimaryBar;
   public virtual ICollection<> Bars;
}
public class Bar {
   public Guid BarId;
   public Guid FooId;
   public virtual Foo PrimaryBarOfFoo;
   public virtual Foo Foo;
}

这是使用流利的api指定一对一关系的方法:

modelBuilder.Entity<Bar>()
            .HasOptional(p => p.PrimaryBarOfFoo)
            .WithOptionalPrincipal(o => o.PrimaryBar)
            .Map(x => x.MapKey("PrimaryBarId"));

请注意,添加时PrimaryBarId需要删除,因为我们通过流利的api指定添加。

另请注意,方法名称[WithOptionalPrincipal()][1]具有讽刺意味。在这种情况下,Principal是Bar。msdn上的WithOptionalDependent()描述使其更加清晰。


2
如果您实际上想要PrimaryBarId房产怎么办?这对我来说太荒谬了。如果添加属性并说它是外键,则会出现错误。但是,如果我没有该属性,那么EF仍然会创建它。有什么不同?
克里斯·普拉特

1
@ChrisPratt这听起来可能不合理。经过反复试验,我得出了这个解决方案。当我PrimayBarIdFoo实体中拥有属性时,无法配置一对一映射。可能与您尝试过的解决方案相同。EF的局限性?
Sudarshan_SMD

3
是啊,就是。我发现迄今为止,EF从未实现过唯一索引。结果,唯一可用的一对一映射方法是将主端的主键用作从属端的主键,因为主键本质上是唯一的。换句话说,他们实现了一半,并采取了一条捷径,该捷径指示必须以非标准方式设计表。
克里斯·普拉特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.