RomeoQNgo
RomeoQNgo

Reputation: 43

inheritance for EF code first. mixture of TPH and TPT

Interesting inheritance for EF code first. Do you think there is a mapping strategy that can make this work?

So I have a base abstract class called “Animal” and 3 derived classes from the Animal class, Fish, Dog, and UnknownAnimal. Animal class has a SQL table of its own, Fish and Dog has SQL table Fish and Dog respectively. UnknownAnimal does not have any extra fields so there is no need a SQL table for this class. To make it a bit easier, Animal SQL Table has a discriminator column (TypeName) to determine the Animal type.

The codes and a picture of the SQL tables is below. It is neither TPH or TPT but a mixture. The only solution I see is to make it TPT, by creating a SQL table “UnknownAnimal” and point UnknownAnimal Class to use this table. But I do not want to approach this way since UnknownAnimal does not have any extra property and is taking up space in the SQL server (not much).

Code for full test project with integration Nunit test and even database .bak file. https://bitbucket.org/RomeoQNgo/efinheritancetest/downloads

I tried TPT but that required an extra UnknownAnimal SQL table. That mean if I have another class like UnknownAnimal (inherit from Animal but has no extra property) then I have to create a new table for it. One easy approach would be have a discriminator field called something like TypeName in the Animal SQL Table and let that determine class type. But then I don’t want to use TPH because if there are more animal type with new property unique for that animal (like elephant with property like TrunkLength) then we have to create a new column in the Animals SQL table which I don’t want to go this path unless there are no possible way.

So I want to combine both TPH and TPT which use discriminator field (TypeName) to determine class type and extra table for the animal’s extra properties unique for that class. I want to use Code First and do not want to use any EDMX file for this.

I wonder if there are any good approach for this currently with EF Code First. Thank you for your helps in advance.

public interface IEntity2
{
    string Creator { get; set; }
}

public interface IEntity
{
    int Id { get; set; }
    string DisplayName { get; set; }
}

[Table("Animals")]
public abstract class Animal : IEntity, IEntity2
{
    public virtual int Id { get; set; }
    public virtual string DisplayName { get; set; }
    public virtual int TotalLegs { get; set; }
    public string Creator { get; set; }
}

[Table("UnknownAnimals")]
public class UnknownAnimal : Animal
{
    int test { get { return 1; } }
}

[Table("Fishes")]
public class Fish : Animal
{
    public virtual int WaterType { get; set; }
}

[Table("Dogs")]
public class Dog : Animal
{
    public virtual int FurLength { get; set; }
}

The database diagram is:

https://i.sstatic.net/4JiCJ.png

Upvotes: 2

Views: 1126

Answers (1)

Gert Arnold
Gert Arnold

Reputation: 109080

Somehow it does not seem right to have a class UnknownAnimal (although I realize it's just an abstraction of your real life code). Semantically, an unknown animal is an Animal but it hasn't got a type (yet?). It might be a better reflection of reality to just store it as an Animal, by making the Animal class not abstract. Doing so, you don't need an UnknownAnimal table and the discriminator column is still not required.

But you will never be able to get UnknownAnimals only from the database easily, because context.Animals.OfType<Animal>() returns all animals. [Personally, I prefer only the leaves of an inheritance tree to be concrete types, but that may be some congenital mental defect.]

For me, the question would be: is UnknownAnimal a type in its own right? If so, use the type and take a relatively useless table for granted (it may develop its own fields later on). If not, inheritance is probably not the right model here and you should use composition (which some argue is always better than inheritance).

Upvotes: 2

Related Questions