Code First Entity Framework 6: 1 to 1 with composite key
Code First Entity Framework 6: 1 to 1 with composite key
我继承了一个遗留的 SQL 数据库,我正试图将其逆向工程到 Code First 中。由于当前配置上的遗留软件 运行,无法更改架构。令我感到奇怪的是,开发人员将子 table 配置为具有由 ChildId + ParentId 组成的复合主键,而不仅仅是 ParentId。
这是我的:
public class Parent
{
public decimal PkParentId { get; set; }
public string ParentName { get; set; }
...
public Child Child { get; set; }
}
public class Child
{
public decimal PkChildId { get; set; }
public decimal PkParentId { get; set; }
public string ChildName { get; set; }
...
public Parent Parent { get; set; }
}
这是我的映射。当我对它进行逆向工程时,EF 想创建一个 1 对多的父子集合,但我真的想要一个 1 对 0 或 1(一个子子可能存在也可能不存在,但父子必须存在)。
public class ParentConfiguration : EntityTypeConfiguration<Parent>
{
public ParentConfiguration()
{
HasKey(p => p.PkParentId);
Property(p => p.PkParentId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasOptional(p => p.Child).WithRequired(p => p.Parent);
// Also tried this
// HasOptional(p => p.Child).WithRequired(p => p.Parent).Map(p => p.MapKey("PkParentId"));
}
}
public class ChildConfiguration : EntityTypeConfiguration<Child>
{
public ChildConfiguration()
{
// Pk is composite on child
HasKey(e => new {e.PkChildId, e.PkParentId});
Property(p => p.PkChildId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
我可以一起获取父子关系没问题,但是如果我尝试插入父子关系:
var newParent = new Parent
{
ParentName = "XXX",
Child = new Child { ChildName = "YYY" }
};
_dbContext.Parents.Add(newParent);
_dbContext.SaveChanges();
这会导致以下错误:在 SET 子句中多次指定列名 'PkParentId'。在同一 SET 子句中不能为一列分配多个值。修改 SET 子句以确保列只更新一次。如果 SET 子句更新视图的列,则列名 'PkParentId' 可能会在视图定义中出现两次。
果然,如果检查生成的 SQL,它会尝试使用子插入插入 PkParentId 两次,一次作为第一个参数,一次作为 last.It,就像 EF 没有放置一样PkParentId 一起是父导航的外键 属性 所以我试图将它添加到子配置中:
HasRequired(x => x.Parent).WithOptional(y => y.Child).Map(z => z.MapKey("PkParentId"));
这会产生同样的错误。奇怪的是,我找不到可以让我使用 "HasForeignKey" 的 Optional 关系,但 WithMany() 会强制我返回 1:M.
EF 中的 One-to-one 始终包含一个主键,该主键也是一个外键。 child 的主键复制其 parent 的值并通过 FK 约束引用它们。
但是 child 的主键与 parent 的主键非常匹配!而事实并非如此。
但这只有你知道。 EF 不必知道 Child
有复合键。通过将 PkChildId
标记为已计算来稍微欺骗 EF:
public ChildConfiguration()
{
// Pk is composite on child
HasKey(e => e.PkParentId);
Property(p => p.PkChildId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
}
现在 EF 将只能通过 PkParentId
识别 Parent
s 和 Child
ren,当插入 Child
时,它只会读取 PkChildId
来自数据库,但不将其用作实体键。
我继承了一个遗留的 SQL 数据库,我正试图将其逆向工程到 Code First 中。由于当前配置上的遗留软件 运行,无法更改架构。令我感到奇怪的是,开发人员将子 table 配置为具有由 ChildId + ParentId 组成的复合主键,而不仅仅是 ParentId。
这是我的:
public class Parent
{
public decimal PkParentId { get; set; }
public string ParentName { get; set; }
...
public Child Child { get; set; }
}
public class Child
{
public decimal PkChildId { get; set; }
public decimal PkParentId { get; set; }
public string ChildName { get; set; }
...
public Parent Parent { get; set; }
}
这是我的映射。当我对它进行逆向工程时,EF 想创建一个 1 对多的父子集合,但我真的想要一个 1 对 0 或 1(一个子子可能存在也可能不存在,但父子必须存在)。
public class ParentConfiguration : EntityTypeConfiguration<Parent>
{
public ParentConfiguration()
{
HasKey(p => p.PkParentId);
Property(p => p.PkParentId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasOptional(p => p.Child).WithRequired(p => p.Parent);
// Also tried this
// HasOptional(p => p.Child).WithRequired(p => p.Parent).Map(p => p.MapKey("PkParentId"));
}
}
public class ChildConfiguration : EntityTypeConfiguration<Child>
{
public ChildConfiguration()
{
// Pk is composite on child
HasKey(e => new {e.PkChildId, e.PkParentId});
Property(p => p.PkChildId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
我可以一起获取父子关系没问题,但是如果我尝试插入父子关系:
var newParent = new Parent
{
ParentName = "XXX",
Child = new Child { ChildName = "YYY" }
};
_dbContext.Parents.Add(newParent);
_dbContext.SaveChanges();
这会导致以下错误:在 SET 子句中多次指定列名 'PkParentId'。在同一 SET 子句中不能为一列分配多个值。修改 SET 子句以确保列只更新一次。如果 SET 子句更新视图的列,则列名 'PkParentId' 可能会在视图定义中出现两次。
果然,如果检查生成的 SQL,它会尝试使用子插入插入 PkParentId 两次,一次作为第一个参数,一次作为 last.It,就像 EF 没有放置一样PkParentId 一起是父导航的外键 属性 所以我试图将它添加到子配置中:
HasRequired(x => x.Parent).WithOptional(y => y.Child).Map(z => z.MapKey("PkParentId"));
这会产生同样的错误。奇怪的是,我找不到可以让我使用 "HasForeignKey" 的 Optional 关系,但 WithMany() 会强制我返回 1:M.
One-to-one 始终包含一个主键,该主键也是一个外键。 child 的主键复制其 parent 的值并通过 FK 约束引用它们。
但是 child 的主键与 parent 的主键非常匹配!而事实并非如此。
但这只有你知道。 EF 不必知道 Child
有复合键。通过将 PkChildId
标记为已计算来稍微欺骗 EF:
public ChildConfiguration()
{
// Pk is composite on child
HasKey(e => e.PkParentId);
Property(p => p.PkChildId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
}
现在 EF 将只能通过 PkParentId
识别 Parent
s 和 Child
ren,当插入 Child
时,它只会读取 PkChildId
来自数据库,但不将其用作实体键。