Entity Framework Model with Table-per-Type Inherit

2019-05-10 08:14发布

问题:

When I define a model in Entity Framework with Table-per-Type Inheritance, if I have a base class/table (not abstract) called person, and two sub entities and tables, adult and child, after creating a child, how would I take the same object and convert it to adult? Once converted to adult, the child record should be deleted, though the base class data in the person table should be retained.

回答1:

It is not possible. It is similar problem like here. Simply the entity exists and its type is immutable. The only way to do that is delete child entity (= records from both tables) and create a new adult entity (= new records for both tables).

This doesn't look like scenario for inheritance at all.

Edit:

The comment about inheritance was targeted for scenario where you mentioned Person, Adult and Child entities. Anyway once your scenario allows changing the type you should think about another solution where the part which can change will be handled by composition.

For example:

public class DataSource
{
    public int Id { get; set; }
    public virtual DataSourceFeatures Features { get; set; }
}

public class DataSourceFeatures
{
    [Key, ForeignKey("DataSource")]
    public int Id { get; set; }
    public virtual DataSource DataSource { get; set; }
}

public class XmlDataSourceFeatures : DataSourceFeatures { ... }

public class DelimitedDataSourceFeatures : DataSourceFeatures { ... }

public class ServiceDataSourceFeatures : DataSourceFeatures { ... }

Now changing a type means deleting dependent current DataSourceFeatures from the database and create a new one but original object remains the same - only relation changes.



回答2:

I wouldn't do this with EF, because with inheritance you've created an object-oriented abstraction over table relationships that doesn't allow you to convert from different types. In OO you can't do thing like this:

Child child = new Child();
Adult grownUp = child;

And then expect the child to be an adult. You'd do it like this:

Child child = new Child();
Adult grownUp = child.GrowUp();

So assuming you're using SQL Server you could do that with a stored procedure. Something like GrowUp(child) and have it create a new entry in the Adult table as well as delete the entry in the Child table, but leave Person untouched. You could return the new adult object from the procedure. This can then be used like this:

Adult grownUp = context.GrowUp(child);

However you'd need to make sure in your code that after this line you don't use the child object anymore and you probably need to refresh or remove it from the context (not entirely sure about this).