1

我有一个像这样的基本继承层次结构:

public class Parent
{
    public int ParentID {get; set;}

    public string SomeOtherProperty {get; set;}
};

public class Child : Parent
{
    public string SomeChildProperty {get; set;}
};

我有多个子类,并且我有一个 Auditor 对象,该对象具有基于 Parent 类的接口,允许我以通用方式写入数据库,如下所示

public class Auditor
{
    public void WriteObject(Parent p)
    {
        using (MyDbContext context = new Context)
        {
            context.Parents.Add(p);
            context.SaveChanges();
        }
    }
}

所以我可以像使用 Auditor

auditor.WriteObject(new Child1());
auditor.WriteObject(new Child2());

等等等等,每当我编写一个子对象时,EF 都会为我在数据库中创建父行。

我遇到的问题是在某些情况下(可能是 10% 的时间),我想将子记录写入数据库并将其链接到现有的父行,即我想提供外键。

我尝试了类似的东西

Child1 child = new Child();
child1.ParentID = existingID;
auditor.WriteObject(child);

但是 EF 忽略了我提供的外键并为我创建了一个新的 Parent 记录。

无论如何让EF理解这一点,因为父ID已经存在于我试图编写的子对象上,它不需要插入父行?

4

1 回答 1

3

根据您的描述,我有点困惑,但会尝试回答我认为您可能意味着的场景:

选项 1:我认为这就是您所追求的:您正在创建父类的对象。稍后,您有更多信息并希望将它们“向下转换”到适当的子类。这在 EF 中是不可能的。一旦对象被创建为特定类型,它就必须保留。那么在您的情况下,选项如下:

  1. 此对象是否已作为 (parentType) 存在
  2. 删除对象(父类型)
  3. 保存对象(ChildType)

看到比我在这里能给出的更好的措辞解释:

将子项添加到实体框架中的现有父记录

使用实体框架向下转型

如果这是您打算做的,我建议应该重新考虑正在实施的模型的某些部分以避免这些情况。

选项 2:您有一个子元素列表,这些子元素作为一个组属于父对象(在这种情况下是超类型):

在这些情况下,您可以加载父级,将子级添加到父级,然后保存(在父级):

Child1 child = new Child();
Parent p = _context.Parents.Find(search based on ID)
p.Children.Add(child);
auditor.WriteObject(p);

更新:选项 3

根据您对共享父 ID 的评论:您现在谈论的不是 TPT 实现,您在这里违反了规则。在 TPT 中,您有一个 ID,它驻留在“父”表中,它是每个对象的所有表中的主键。绝不应该出现两个子对象(任何类型)具有相同主键的情况,并且在所有情况下,子对象的主键都是parentID。使用不太抽象的术语可能有助于消除混淆:如果父表是 Animal 而子表是 Cat 和 Dog 很明显 Cat 和 dog 不会共享主键(因为它们是不同的类型。我想你可能是尝试实现可能是相反的: Child 应该包含 parent 的实例(使用您问题中的术语)。

换一种说法,如果 parentID 是主键,它将只存在于对象层次结构的一个分支中,并且只会用于将构成该对象的继承链拉在一起。例如,如果我有一个像

动物->狗->贵宾犬

我创建了一个 ID=1 的新贵宾犬,我将永远只有一组 ID=1 的记录,并且它将在 Animal、Dog 和 Poodle 中各占一行。(并且所有这三个记录都是针对同一个 Poodle 对象),

于 2013-01-23T20:46:34.683 回答