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 识别 Parents 和 Children,当插入 Child 时,它只会读取 PkChildId 来自数据库,但不将其用作实体键。