I have the following types:
public abstract class Vehicle {
public int Id { get; set; }
public double TopSpeed { get; set; }
}
public class Car : Vehicle {
public int Doors { get; set; }
}
public class Motorcycle : Vehicle {
public string Color { get; set; }
}
And I have a code-first DBContext:
public MyDbContext: DbContext {
public DbSet<Car> Cars { get; set; }
public DbSet<Motorcycle> Motorcycles { get; set; }
}
This works great if I query for a car or moto directly...
var dbContext = new MyDbContext();
var cars = dbContext.Set<Car>().Where(x=> x.TopSpeed>10); // <-- THIS WORKS
But if I want a list of all vehicles, whether car or moto, I would like to do this:
var dbContext = new MyDbContext();
var vehicles = dbContext.Set<Vehicle>().Where(x=> x.TopSpeed>10); // <-- THIS DOES NOT WORK
When I try the above code, I get an exception:
System.InvalidOperationException : The entity type Vehicle is not part of the model for the current context.
That makes perfect sense... I didn't add Vehicle to the context. I added car and moto. At this point, I'm not sure what to do. I tried adding Vehicle to my context, but that combined the tables for car and moto into one Vehicle table. I definitely want a separate table for cars and motos (and possibly a table for the vehicle base properties as well). What's the best way to do this?
Have a Vehicles Properties of type DBSet of Vehicle
in your MyDbContext class.
public MyDbContext: DbContext {
public DbSet<Car> Cars { get; set; }
public DbSet<Motorcycle> Motorcycles { get; set; }
public DbSet<Vehicle> Vehicles { set; get; }
}
Now you can access all vehicles with the criteria like this
var vehicles = dbContext.Set<Vehicle>().Where(x=> x.TopSpeed>10);
Keep in mind that you should have a Key Property in your entity classes ( ID
or {ClassName}ID
). Otherwise it is going to give you a run time error! (Yes the code will compile.)
public abstract class Vehicle
{
public int ID { set; get; }
public double TopSpeed { get; set; }
}
EDIT : As per the comment
By Default Entity Framework will do a Table Per Hierarchy.All Data in the hierarchy is saved in a single table and it use the Discriminator
column to identify which record belongs to which subtype. So As the result you will have one Vehicle table with columns same as properties of All your classes in the hierarchy with an extra column called "Discriminator
". For a Record for Car, It will have the "Car" value inside the Discriminator column.
If you want to create Single table per each type, We will go for Table Per Type. Entity Framework will create a Table for the base class and seperate table for all child classes.
To make this happen, You can use Fluent API to override the configuration.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>().ToTable("Cars");
modelBuilder.Entity<Motorcycle>().ToTable("Motorcycles");
base.OnModelCreating(modelBuilder);
}
And the output is
Now You should be able to query Your Vehicle Entries like this
var vehicles = dbContext.Set<Vehicle>().Where(x => x.TopSpeed > 150).ToList();
And the result is here
Notice that the result contains both MotorCycle
type and Car
type.
Check this link to decide what Inheritance Strategy to use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With