在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; }
}
当我尝试将一些数据插入数据库时,它抛出异常:
{"A dependent property in a ReferentialConstraint is mapped to a
store-generated column. Column: 'Id'."}
我似乎无法为Child2
使用自动生成的ID,如何保留此功能并同时成功建立关系?
答案 0 :(得分:22)
这里有两个问题,显而易见的问题,如例外。定义一对一关系时,FK也必须是PK。在这种情况下,两个实体的PK和FK都是Id
字段。异常中显示的问题是FK是数据库生成的。因此,如果您插入带有相关Child1
的{{1}},则EF无法设置相关Child2
的FK值,因为它是数据库生成的。
第二个问题,仍然没有出现,是一对一的关系只是像SQL Server这样的数据库中的理论事物。如果您要插入取决于Child2
的{{1}},则需要先插入Child1
,然后插入相关的Child2
。这是正确的,但是,ooops,您还必须在插入Child1
之前插入Child2
,因为Child2
还取决于Child1
。因此,不可能实现纯粹的一对一关系。
要解决此问题,您需要做两件事:
最后,如果你想到它,一对一的关系通常是没有意义的。您可以使用包含两个表中所有列的单个表,因为当表A中存在一行时,它必须存在于表B中,反之亦然。因此,拥有单个表具有相同的效果。
但是,如果您仍想使用1对1关系,EF允许您对其进行建模:
Child1
请注意,在这种情况下,EF抽象注意允许您具有1对1的关系,即使它在DB中不存在也是如此。但是,必须使用Child2
指定此关系,因为您需要指定主体和从属端。在这种情况下,主体是modelBuilder.Entity<Child1>()
.HasRequired(c1 => c1.Child2)
.WithRequiredPrincipal(c2 => c2.Child1);
,依赖是ModelBuilder
。请注意,您仍需要注意数据库生成值的规则。
请注意,这是使用从Child1
到Child2
的单个FK而不是从Child2
到Child1
的FK在数据库中建模的。因此,在DB中是(1) - 到(0或1)关系,如上所述
Child1