Reputation: 13012
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?
Upvotes: 5
Views: 1068
Reputation: 431
Using a DataAnnotation.Schema.Table("TableName") entry, on the inherited class, triggers the creation of a new table for the inherited type (table-per-type) and eliminates the Discriminator field in the parent type table, without the need for the Fluent API code.
Upvotes: 0
Reputation: 218852
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.
Upvotes: 11
Reputation: 3432
Have you tried giving Vehicle its own context with just a DBSet? I think that might do it for you.
Upvotes: 0