Reputation: 1326
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?
Upvotes: 1
Views: 1131
Reputation: 9949
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:
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),
Upvotes: 3