简体   繁体   English

在EF4 Code-First中按基类型查询

[英]Querying by base type in EF4 Code-First

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: 我有一个代码优先的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. System.InvalidOperationException:实体类型Vehicle不是当前上下文的模型的一部分。

That makes perfect sense... I didn't add Vehicle to the context. 这很有道理......我没有将Vehicle添加到上下文中。 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. 我尝试将Vehicle添加到我的上下文中,但是将car和moto的表合并到一个Vehicle表中。 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. 在MyDbContext类中拥有类型为DBSet的Vehicle属性。

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 ). 请记住,您的实体类中应该有一个Key Property( ID{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. 默认情况下,实体框架将执行每个层次结构层次结构中的所有数据都保存在单个表中,并使用Discriminator列来标识哪个记录属于哪个子类型。 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 ". 因此,作为结果,您将拥有一个Vehicle表,其列与层次结构中所有类的属性相同,并带有一个名为“ Discriminator ”的额外列。 For a Record for Car, It will have the "Car" value inside the Discriminator column. 对于Car for Record,它将在Discriminator列中包含“Car”值。

在此输入图像描述

If you want to create Single table per each type, We will go for Table Per Type . 如果要为每种类型创建单个表,我们将选择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. 要实现此目的,您可以使用Fluent API覆盖配置。

    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. 请注意,结果包含MotorCycle类型和Car类型。

Check this link to decide what Inheritance Strategy to use. 检查此链接以确定要使用的继承策略。

Have you tried giving Vehicle its own context with just a DBSet? 您是否尝试过仅使用DBSet为Vehicle提供自己的上下文? I think that might do it for you. 我想那可能会为你做。

在继承的类上使用DataAnnotation.Schema.Table(“TableName”)条目,触发为继承类型(table-per-type)创建新表,并消除父类型表中的Discriminator字段,而不是需要Fluent API代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM