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

时间:2012-05-02 19:06:04

标签: c# entity-framework inheritance

我有以下类型:

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; }
}

我有一个代码优先的DBContext:

public MyDbContext: DbContext { 
    public DbSet<Car> Cars { get; set; }
    public DbSet<Motorcycle> Motorcycles { get; set; }
}

如果我直接查询汽车或摩托车,这很有用......

var dbContext = new MyDbContext();
var cars = dbContext.Set<Car>().Where(x=> x.TopSpeed>10); // <-- THIS WORKS

但如果我想要所有车辆的清单,无论是汽车还是摩托车,我都想这样做:

var dbContext = new MyDbContext();
var vehicles = dbContext.Set<Vehicle>().Where(x=> x.TopSpeed>10); // <-- THIS DOES NOT WORK

当我尝试上面的代码时,我得到一个例外:

  

System.InvalidOperationException:实体类型Vehicle不是部分   当前背景下的模型。

这很有道理......我没有将Vehicle添加到上下文中。我加了汽车和摩托车。在这一点上,我不知道该怎么做。我尝试将Vehicle添加到我的上下文中,但是将car和moto的表合并到一个Vehicle表中。我当然想要一个单独的汽车和摩托车桌子(也可能是车辆基地属性的桌子)。最好的方法是什么?

3 个答案:

答案 0 :(得分:11)

在MyDbContext类中拥有Vehicle类型的DBSet的车辆属性。

public MyDbContext: DbContext { 
    public DbSet<Car> Cars { get; set; }
    public DbSet<Motorcycle> Motorcycles { get; set; }
    public DbSet<Vehicle> Vehicles { set; get; }
}

现在您可以使用这样的标准访问所有车辆

var vehicles = dbContext.Set<Vehicle>().Where(x=> x.TopSpeed>10);

请注意,您的实体类(ID{ClassName}ID)中应该有一个Key Property。否则它会给你一个运行时错误! (是的,代码将编译。)

public abstract class Vehicle
{
    public int ID { set; get; }
    public double TopSpeed { get; set; }
}

编辑:根据评论

默认实体框架将执行每个层次结构表。层次结构中的所有数据都保存在单个表中,并使用Discriminator列来标识哪个记录属于哪个子类型。因此,作为结果,您将拥有一个Vehicle表,其列与层次结构中所有类的属性相同,并带有一个名为“Discriminator”的额外列。对于Car for Car,它将在Discriminator列中包含“Car”值。

enter image description here

如果您想为每种类型创建单个表格,我们将选择每种类型的表格。实体框架将为所有子类的基类和单独表创建一个表。

要实现此目的,您可以使用Fluent API覆盖配置。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Car>().ToTable("Cars");
        modelBuilder.Entity<Motorcycle>().ToTable("Motorcycles");

        base.OnModelCreating(modelBuilder);
    }

输出

enter image description here

现在您应该能够像这样查询您的车辆参赛作品

 var vehicles = dbContext.Set<Vehicle>().Where(x => x.TopSpeed > 150).ToList();

结果就在这里

enter image description here

请注意,结果包含MotorCycle类型和Car类型。

选中此link以确定要使用的继承策略。

答案 1 :(得分:0)

您是否尝试过仅使用DBSet为Vehicle提供自己的上下文?我想那可能会为你做。

答案 2 :(得分:0)

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