Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Table-per-type inheritance with EF 4.1 Fluent Code First

I have a pretty straight forward set of database tables, like:

Vehicle
 Id
 RegNo

Car
 Id (FK of Vehicle.Id)
 OtherStuff

Bike
 Id (FK of Vehicle.Id)
 MoreStuff

My class model is as you'd expect: with Vehicle being an abstract class, and then Car and Bike being subclasses of it.

I have setup my EF4.1 Code First configuration as follows:

class VehicleConfiguration : EntityTypeConfiguration<Vehicle> {
    public VehicleConfiguration() {
        ToTable("Vehicles");
        Property(x => x.Id);
        Property(x => x.RegNo);
        HasKey(x => x.Id);
    }
}

class CarConfiguration : EntityTypeConfiguration<Car> {
    public CarConfiguration() {
        ToTable("Cars");
        Property(x => x.OtherStuff);
    }
}

class BikeConfiguration : EntityTypeConfiguration<Bike> {
    public BikeConfiguration() {
        ToTable("Bikes");
        Property(x => x.MoreStuff);
    }
}

However I am getting numerous strange exceptions when EF tried to build its model configuration.

Currently it is throwing out this:

System.Data.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Invalid column name 'Discriminator'.

Where is it getting that column name from? It's not in any of my code or the database itself. It must be some convention that's taking over control. How do I instruct EF to use table-per-type?

If I remove the "abstract" keyword from my Vehicle class (which I did as a sanity test somewhere along the line) then I get a different exception like the following:

(35,10) : error 3032: Problem in mapping fragments starting at lines 30, 35:EntityTypes AcmeCorp.Car, AcmeCorp.Bike are being mapped to the same rows in table Vehicles. Mapping conditions can be used to distinguish the rows that these types are mapped to.

I'm obviously doing something terribly wrong, but what? I've followed the MSDN docs and all the other TPT + EF4.1 articles I can find!

like image 745
nbevans Avatar asked Jun 30 '11 16:06

nbevans


People also ask

Which of the following are inheritance strategies can be used with EF Code First?

Inheritance with EF Code First: Table per Hierarchy (TPH)

What is Table Per Hierarchy in Entity Framework?

Table-per-hierarchy and discriminator configuration. By default, EF maps the inheritance using the table-per-hierarchy (TPH) pattern. TPH uses a single table to store the data for all types in the hierarchy, and a discriminator column is used to identify which type each row represents.

Which is a Fluent API method that can be used to configure a default value for the column that the property maps to?

The Entity Framework Core Fluent API HasDefaultValue method is used to specify the default value for a database column mapped to a property. The value must be a constant.


2 Answers

Have you read the following article?

It is a 3 part article covering the following approaches

  1. Table per Hierarchy (TPH): Enable polymorphism by denormalizing the SQL schema, and utilize a type discriminator column that holds type information.

  2. Table per Type (TPT): Represent "is a" (inheritance) relationships as "has a" (foreign key) relationships.

  3. Table per Concrete class (TPC): Discard polymorphism and inheritance relationships completely from the SQL schema.

like image 169
thmsn Avatar answered Nov 02 '22 22:11

thmsn


When I had this problem, I discovered that I had a subclass that was not mapped. In this example, some possible causes of this are:

  1. An additional subclass exists, such as Bus. This is not mapped.
  2. One of the subclasses, such as Car, is not mapped.

In this case, ensure that every subclass is mapped:

  1. Ensure a mapping exists for the subclass, including a ToTable method call.
  2. Ensure the mapping is actually being applied during OnModelCreating.
  3. If you have trouble tracking this, try using a debugger and setting breakpoints in all of the mapping code.

Alternatively, if the subclass shouldn't be mapped in the first place, ensure that it is ignored by using one of the Ignore method calls.

like image 26
Sam Avatar answered Nov 02 '22 20:11

Sam