ReferentialConstraint中的依赖属性以1对1的关系映射到存储生成的列错误

Jer*_*ian 8 entity-framework ef-code-first

在EntityFramework代码的第一个模型中,存在1:1的关系:

public class Child1
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    public Child2 Child2 { get; set; }
}

public class Child2
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [ForeignKey("Child1")]
    public int Id { get; set; }

    public string Name { get; set; }

    public Child1 Child1 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试将一些数据插入数据库时​​,它抛出异常:

{"A dependent property in a ReferentialConstraint is mapped to a 
  store-generated column. Column: 'Id'."}
Run Code Online (Sandbox Code Playgroud)

似乎我不能使用自动生成的Id Child2,如何保持此功能并同时成功建立关系?

Jot*_*aBe 22

这里有两个问题,显而易见的问题,如例外.定义一对一关系时,FK也必须是PK.在这种情况下,两个实体的PK和FK都是该Id字段.异常中显示的问题是FK是数据库生成的.因此,如果插入Child1带有相关的Child2,则EF无法设置相关的FK值,Child2因为它是数据库生成的.

第二个问题,即尚未出现,是一对一的关系只是像SQL Server这样的数据库中的理论问题.如果要插入Child1依赖Child2,则需要先插入Child1,然后再插入相关内容Child2.这是对的,但是,ooops,你也必须在插入Child2之前插入Child1,因为Child1还要依赖Child2.因此,拥有纯粹的一对一关系是不可能的.

要解决这个问题,您需要做两件事:

  1. 使关系为1到0(0或1).即你必须有一个主要实体和一个可以存在或不存在的依赖实体.这将允许您插入主体实体,而不需要依赖实体,因为使用此配置,您可以在不使用依赖项的情况下使主体成为实体.
  2. 主PK可以保留为数据库生成,但您必须更改依赖实体上的PK而不是db生成的.因此,当您插入从属实体时,PK(也是FK)可以由EF自由指定.

最后,如果你想到它,一对一的关系通常是没有意义的.您可以使用包含两个表中所有列的单个表,因为当表A中存在一行时,它必须存在于表B中,反之亦然.因此,使用单个表具有相同的效果.

但是,如果您仍想使用1对1关系,EF允许您对其进行建模:

modelBuilder.Entity<Child1>()
            .HasRequired(c1 => c1.Child2)
            .WithRequiredPrincipal(c2 => c2.Child1);
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,EF抽象注意允许您具有一对一的关系,即使它在DB中不存在.但是,必须使用the指定此关系,ModelBuilder因为您需要指定主体和从属端.在这种情况下,主体是Child1和依赖的Child2.请注意,您仍然需要注意数据库生成值的规则.

请注意,这是在DB中使用单个FK Child2从而建模的Child1,而不是从FK Child1Child2.因此,在DB中是(1)到(0或1)关系,如上所述

public class Child1
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  // Leave as is
    public int Id { get; set; }
    ...


public class Child2
{
    //[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]  // Not db-generated
    //[ForeignKey("Child1")] -- specified in the model builder
    public int Id { get; set; }
Run Code Online (Sandbox Code Playgroud)