代码第一TPT继承 - 如何提供外键代替EF为我创建父行? [英] Code First TPT Inheritance - How can I supply the foreign key instead of EF creating the parent row for me?

查看:169
本文介绍了代码第一TPT继承 - 如何提供外键代替EF为我创建父行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  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());

等等,每当我写一个Child对象时,EF在DB中创建了Parent行我。



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



我尝试过像

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

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



有没有办法让EF了解,因为父代码已经存在于我正在尝试写入的Child对象上,它不需要插入父行?

解决方案

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

选项1 :我认为这是你以后:您正在创建父类的对象。之后,你有更多的信息,并希望'downcast'他们到适当的子类。这是不可能的这样用EF。一旦将对象创建为特定类型,就是必须保留的对象。您的情况下的选项如下:


  1. 此对象是否已存在(parentType)

  2. 删除对象(ParentType)

  3. 保存对象(ChildType)

比我可以在这里:



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



使用实体框架进行裁剪



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



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



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

  Child1 child = new Child(); 
父p = _context.Parents.Find(根据ID搜索)
p.Children.Add(child);
auditor.WriteObject(p);

更新:选项3



根据您对共享父ID的评论:您现在正在谈论的不是TPT实现,而是在这里打破规则。在TPT中,您有一个位于父表中的单个ID,它是每个对象的所有表的主键。不应该有两个子对象(任何类型)具有相同的主键,并且在所有情况下都是一个子主键 IS parentID。使用较少的抽象术语可能有助于消除混淆:如果父表是动物,并且小孩表是猫和狗,很明显,猫和狗不会共享主键(因为它们是不同的类型,我想你可能是尝试实现可能是相反的:一个孩子应该包含一个父类的实例(使用您的问题的术语)。



再说一句,如果parentID是主键只存在于对象层次结构的一个分支中,并且仅用于将构成该对象的继承链拉在一起,例如如果我有一个层次结构,如



Animal-> Dog-> Poodle



我创建了一个ID = 1的新的狮子狗,我只会有一套记录ID = 1,动物,狗和狮子狗中的每一行都是一行(所有这三个记录都是相同的Poodle对象),


I have a basic inheritance hierarchy like this:

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

    public string SomeOtherProperty {get; set;}
};

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

I have multiple child classes and I have an Auditor object that has an interface based on the Parent class that allows me to write to the database in a generic way, like this

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

So I can use Auditor like

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

etc, etc, and whenever I write a Child object, EF created the Parent row in the DB for me.

The problem I'm having is in some cases (maybe 10% of the time), I want to write a Child record to the DB and link it to an existing Parent row, i.e. I want to supply the foreign key.

I tried something like

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

But EF ignored the foreign key I supplied and created a new Parent record for me.

Is there anyway to get EF to understand that, since the parent ID already exists on the Child object I'm trying to write, that it doesn't need to insert the parent row?

解决方案

I am a little confused based on your description, but will try to answer the scenarios I think you might mean:

Option 1: I think this is what you are after: You are creating objects of the parent class. Later, you have more information and want to 'downcast' them to the appropriate subclass. This is not possible in this way with EF. Once the object is created as a specific type that is what it must remain. The option then in your case is the following:

  1. Does this object already exist as (parentType)
  2. Delete Object(ParentType)
  3. Save object (ChildType)

See better worded explainations than I could give here:

Add child to existing parent record in entity framework

Downcasting with Entity Framework

If this is what you are intending to do I would suggest that some part of the model being implemented should be reconsidered to avoid these situations.

Option 2: You have a list of child elements which belong as a group to a parent object (in this case of a super-type):

In these cases you can load the parent, add the child to the parent and then save (at the parent level):

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

UPDATE: Option 3

Based on your comment of shared parent id: what you are talking about now is not a TPT implementation and you are breaking a rule here. In TPT you have a single ID which resides in the 'parent' table which is the primary key across all tables for each object. There should never be a case where two child objects (of any type) have the same primary key, and in all cases a childs primary key IS the parentID. Using less abstract terms might help remove the confusion: if the parent table is Animal and the child tables are Cat and Dog it becomes obvious that Cat and dog would not share a primary key (as they are different types. I think what you might be attempting to achieve is possibly the inverse: a Child should contain an instance of parent (using the terminology from your question).

To say this one more way, if parentID is the primary key it will only exist in one branch of the hierarchy of objects, and will only serve to pull together the chain of inheritance which makes up this object. For example if I have an hierarchy like

Animal->Dog->Poodle

and I create a new poodle with ID=1, I will only ever have one set of records with ID=1, and it will be one row in each of Animal, Dog and Poodle. (and all three of these records are for the same Poodle object),

这篇关于代码第一TPT继承 - 如何提供外键代替EF为我创建父行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆