2012-05-02 27 views
5

我有以下幾種類型:查詢在EF4基類型代碼優先

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表。我絕對想要一個單獨的汽車和摩托車表(也可能是一個車輛基地屬性表)。什麼是最好的方法來做到這一點?

+0

EF不是我的東西,但是如果將它添加到上下文中,您是否可以通過接口獲得一組設置?將'Vehicle'改成'IVehicle'? – Eli

回答

11

在您的MyDbContext類中有車輛屬性DBSet類型爲Vehicle

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)鍵屬性。否則,它會給你一個運行時錯誤! (是的代碼進行編譯。)

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

編輯:按照註釋

默認情況下,實體框架將在層次結構做了表每一個分層。所有數據保存在一個單一的表,它使用Discriminator列來標識哪個記錄屬於哪個子類型。因此,結果是您將有一個Vehicle表的列與層次結構中所有類的屬性相同,並有一個名爲「Discriminator」的額外列。對於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以決定使用何種繼承策略。

+0

正確。我忘記在我的例子中包含id道具。 –

+0

試過這個,它將我的汽車和摩托車組合成一張名爲車輛的表格。我想要一個類型的表。 –

+0

@ByronSommardahl:看到我更新的答案。 – Shyju

0

你有沒有試過只給DBSet賦予Vehicle自己的上下文?我想這可能會爲你做。

+0

當我這樣做時,查詢起作用,但表格被搗毀成一個。在它是每個表類型之前...不是每個表的層次結構。 –

+0

所以爲了清楚你有一個VehicleDbContext和一個MyDbContext(與汽車和摩托)它仍然創建一個名爲Vehicle的表?你用什麼來創建表格?另外,您是否嘗試過使用EDMX編寫器來確保繼承與您的計劃完全相同? –

0

在繼承的類上使用DataAnnotation.Schema.Table(「TableName」)條目觸發爲繼承類型(table-per-type)創建新表,並消除父類型中的Discriminator字段表,而不需要Fluent API代碼。