2012-05-02 17 views
5

tôi có các loại sau:Truy vấn theo loại cơ sở trong EF4 Code-First

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

Và tôi có một DBContext mã đầu tiên:

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

này hoạt động tuyệt vời nếu tôi truy vấn cho một chiếc xe hoặc moto trực tiếp ...

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

Nhưng nếu tôi muốn có một danh sách của tất cả các loại xe, cho dù xe hơi hoặc xe máy, tôi muốn làm điều này:

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

Khi tôi cố gắng đoạn mã trên, tôi nhận được một ngoại lệ:

System.InvalidOperationException: Loại thực thể xe không phải là một phần của mô hình cho bối cảnh hiện nay.

Điều đó có ý nghĩa hoàn hảo ... Tôi không thêm Xe vào ngữ cảnh. Tôi đã thêm xe và moto. Tại thời điểm này, tôi không chắc chắn phải làm gì. Tôi đã thử thêm xe vào bối cảnh của tôi, nhưng kết hợp các bảng cho ô tô và xe máy vào một bảng xe. Tôi chắc chắn muốn có một bảng riêng biệt cho xe ô tô và motos (và có thể là một bảng cho các tài sản cơ sở xe là tốt). Cách tốt nhất để làm điều này là gì?

+0

EF không phải là điều của tôi, nhưng bạn có thể có được một bộ thông qua giao diện nếu bạn thêm nó vào ngữ cảnh, ví dụ: thay đổi 'Xe' thành 'IVehicle'? – Eli

Trả lời

11

Có xe thuộc tính loại DBSet Vehicle trong lớp MyDbContext của bạn.

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

Bây giờ bạn có thể truy cập vào tất cả các xe với các tiêu chí như thế này

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

Hãy ghi nhớ rằng bạn nên có một tài sản quan trọng trong các lớp thực thể của bạn (ID hoặc {ClassName}ID). Nếu không, nó sẽ cho bạn một lỗi thời gian chạy! (Có mã sẽ biên dịch.)

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

EDIT: Theo nhận xét

By Mặc định Entity Framework sẽ làm một bảng mỗi Hierarchy .Tất cả dữ liệu trong hệ thống phân cấp được lưu trong một đơn và sử dụng cột Discriminator để xác định bản ghi nào thuộc về loại phụ nào. Vì vậy, Kết quả là bạn sẽ có một bảng Xe với các cột giống như các thuộc tính của Tất cả các lớp của bạn trong hệ thống phân cấp với một cột phụ được gọi là "Discriminator". Đối với một bản ghi cho ô tô, nó sẽ có giá trị "xe hơi" bên trong cột Discriminator.

enter image description here

Nếu bạn muốn tạo bảng đơn cho mỗi loại, Chúng tôi sẽ đi cho Bảng mỗi Loại. Entity Framework sẽ tạo một bảng cho lớp cơ sở và bảng riêng biệt cho tất cả các lớp con.

Để thực hiện điều này, bạn có thể sử dụng API thông thạo để ghi đè cấu hình.

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

     base.OnModelCreating(modelBuilder); 
    } 

Và đầu ra là

enter image description here

Bây giờ bạn sẽ có thể truy vấn xe của bạn Entries như thế này

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

Và kết quả là đây

enter image description here

Lưu ý rằng kết quả chứa cả hai loại MotorCycle và loại Car.

Kiểm tra điều này link để quyết định chiến lược thừa kế nào sẽ sử dụng.

+0

Chính xác. Tôi quên bao gồm các id prop trong ví dụ của tôi. –

+0

Đã thử điều này và nó kết hợp xe ô tô và motos của tôi vào một bảng gọi là xe cộ. Tôi muốn một bảng cho mỗi loại. –

+0

@ByronSommardahl: Xem câu trả lời cập nhật của tôi. – Shyju

0

Bạn đã thử cung cấp cho xe bối cảnh riêng của mình chỉ với một DBSet? Tôi nghĩ rằng có thể làm điều đó cho bạn.

+0

Truy vấn hoạt động khi tôi làm điều này, nhưng các bảng được đập thành một. Trước khi nó là bảng cho mỗi loại ... không phải là bảng trên mỗi phân cấp. –

+0

Vì vậy, chỉ để được rõ ràng bạn có một VehicleDbContext và một MyDbContext (với xe ô tô và moto) nó vẫn tạo ra một bảng gọi là xe? Bạn đang sử dụng cái gì để tạo các bảng? Ngoài ra, bạn đã thử sử dụng trình soạn thảo EDMX trên nó để đảm bảo rằng sự kế thừa chính xác như bạn đã lên kế hoạch? –

0

Sử dụng mục nhập DataAnnotation.Schema.Table ("TableName"), trên lớp được thừa kế, kích hoạt tạo bảng mới cho loại được thừa kế (bảng mỗi loại) và loại bỏ trường Discriminator trong loại cha mẹ bảng, mà không cần mã Fluent API.

Các vấn đề liên quan