【问题标题】:Entity Framework - Parent to Children When Child Has Composite Primary Key - Insert Error实体框架 - 当子级具有复合主键时的父级 - 插入错误
【发布时间】:2014-05-10 13:47:13
【问题描述】:

我有以下两个类:

public class Parent
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Child> Children { get; set; }

    public Parent()
    {
        Children = new List<Child>();
    }
}

public class Child
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int? ParentId { get; set; }
    public virtual Parent Parent { get; set; }
}

然后是数据上下文中的 Fluent 设置:

modelBuilder.Entity<Child>()
                .HasKey(c => new { c.Id, c.ParentId })
                .HasOptional(c => c.Parent)
                .WithMany(p => p.Children)
                .WillCascadeOnDelete(true);

我这样做是为了在我说 parent.Children.Remove(aChild); 时实际上删除子对象,而不仅仅是将其 ParentId 设置为 null。

问题是,我收到错误“违反主键约束 'PK_dbo.Child'。无法在对象 'dbo.Child' 中插入重复键。重复键值为 (0, 2)。”当我创建一个有孩子的新父母,然后db.SaveChanges()

Parent p = new Parent { Name = "Quarterbacks" };
            p.Children.Add(new Child { Name = "Brady" });
            p.Children.Add(new Child { Name = "P. Manning" });
            p.Children.Add(new Child { Name = "Kaepernick" });
            p.Children.Add(new Child { Name = "Wilson" });
            p.Children.Add(new Child { Name = "Rodgers" });

            db.Parents.Add(p);

            db.SaveChanges();

我认为整数主键是在插入时自动生成的。我该怎么办?我应该将键更改为字符串并在 C# 中创建 GUID 键以使其正常工作吗?

【问题讨论】:

  • 您是否尝试在子实体 ID 之上添加关键属性。我知道您已经通过 fluentapi 进行操作。我会使用 sql profiler 来查看 sql server 中生成的内容。
  • 设置为Cascade-on-Delete,不要用可选部分组成假密钥。
  • 删除时的级联将起作用,但那是当我删除父级时,它的子级也将被删除。问题是, parent.Children.Remove(child) 只是删除关系,而不是从数据库中删除子项。
  • 那是因为你说.HasOptional(c =&gt; c.Parent)
  • 将所有键更改为字符串,并在 C# 中手动生成 GUID,并将 .HasOptional 更改为 .HasRequired - 按预期工作。我只是不明白为什么它不适用于整数。

标签: c# sql entity-framework ef-code-first


【解决方案1】:

我相信对于 composite 键,键的任何部分都不会被标记为身份默认情况下,即使对于整数键也不例外(对于简单的,非复合键)。您可能必须将Identity 选项显式添加到Child 实体的Id 属性:

modelBuilder.Entity<Child>()
    .Property(c => c.Id)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

我有点担心Child 密钥的第二部分可以为空。也许 EF 确实允许这样做,但数据库不一定:我认为,对于 SQL Server,例如可以为空的关键部分是被禁止的。也许,其他数据库可以处理。您显然的目标是识别关系(从父级中删除子级时从数据库中删除子级的关系),但是需要父子之间的必需(非可选)关系,据我所知。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-05
    • 2022-01-11
    • 2020-07-21
    相关资源
    最近更新 更多