.net 代码优先TPT继承-如何提供外键而不是EF为我创建父行?

.net 代码优先TPT继承-如何提供外键而不是EF为我创建父行?,.net,entity-framework,ef-code-first,.net,Entity Framework,Ef Code First,我有一个基本的继承层次结构,如下所示: public class Parent { public int ParentID {get; set;} public string SomeOtherProperty {get; set;} }; public class Child : Parent { public string SomeChildProperty {get; set;} }; 我有多个子类,我有一个Auditor对象,它有一个基于父类的接口,允许我以

我有一个基本的继承层次结构,如下所示:

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

    public string SomeOtherProperty {get; set;}
};

public class Child : Parent
{
    public string SomeChildProperty {get; set;}
};
我有多个子类,我有一个Auditor对象,它有一个基于父类的接口,允许我以通用方式写入数据库,如下所示

public class Auditor
{
    public void WriteObject(Parent p)
    {
        using (MyDbContext context = new Context)
        {
            context.Parents.Add(p);
            context.SaveChanges();
        }
    }
}
所以我可以像这样使用审核员

auditor.WriteObject(new Child1());
auditor.WriteObject(new Child2());
等等,等等,每当我写一个子对象时,EF就会在DB中为我创建父行

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

我试过类似的东西

Child1 child = new Child();
child1.ParentID = existingID;
auditor.WriteObject(child);
但是EF忽略了我提供的外键,并为我创建了一个新的父记录


有没有办法让EF理解,由于父ID已经存在于我试图写入的子对象上,它不需要插入父行?

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

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

  • 此对象是否已作为(父类型)存在
  • 删除对象(父类型)
  • 保存对象(子类型)
  • 看到比我在这里能给出的更好的解释:

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

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

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

    更新:选项3

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

    还有一种说法,如果parentID是主键,那么它将只存在于对象层次结构的一个分支中,并且只用于将构成该对象的继承链拉到一起

    动物->狗->狮子狗


    我创建了一个ID=1的新卷毛狗,我只会有一组ID=1的记录,在动物、狗和卷毛狗中各有一行,

    嗨,Matthew。我想要的是选项2。我知道我可以按照你的建议去做,但是我很犹豫。我正在尝试保持父类的通用性,并允许应用程序通过子类来扩展它。如果我向父类添加子类集合,父类就不再是通用的。你的评论实际上让我认为你仍然是通用的谈到选项1(或者可能是两者的混合)。您的代码让我想到的是,在某些情况下,父对象已经存在,并且您正在将其“扩展”为子类型对象(尝试设置父ID)。在您的情况下,父对象是否可以是抽象类?如果目的是允许某人稍后加载父对象,将其扩展为子类型,添加详细信息,然后重新保存,则需要遵循选项1中的方法。您是对的……我键入得太快,意思是说选项1。我无法删除与父对象对应的数据库行ype实例,因为该行可能是其他子类型的父行。这意味着父行是通过保存另一个子类型创建的,我希望使用此子类型锁定它。可能我唯一的选择是返回到一个良好的旧ADO.NET存储过程:)我更新了我的答案-我认为你还不需要放弃这场斗争,我只是认为你没有意识到,虽然你可能有一个TPT解决方案,但你目前正试图滥用它来完成这项任务。:)嗨,Matthew。在阅读了您的更新并自己做了更多工作之后,我得出了相同的结论——我在这里错误地使用了TPT继承。我重新编写代码,只使用标准的一对多外键关系。谢谢你帮我度过难关!为什么孩子继承父母?孩子不应该有父母财产吗?嗨,Usr。是的,子级可以有父属性,但这将建立外键关系,而不是继承关系。
    Child1 child = new Child();
    Parent p = _context.Parents.Find(search based on ID)
    p.Children.Add(child);
    auditor.WriteObject(p);