2012-05-02 4 views
5

mam następujące typy:Zapytania o typie bazowym w EF4 Kodeksu pierwszego

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

I mam kodu pierwszego DBContext:

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

Działa to doskonale, jeśli zapytać o samochodzie lub bezpośrednio moto ...

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

Ale jeśli chcę listy wszystkich pojazdów, czy samochód lub moto, chciałbym to zrobić:

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

Gdy próbuję powyższy kod, otrzymuję wyjątek:

System.InvalidOperationException: rodzaj podmiotu pojazd nie jest częścią modelu dla bieżącego kontekstu.

To ma sens ... Nie dodawałem pojazdu do kontekstu. Dodałem samochód i moto. W tym momencie nie jestem pewien, co robić. Próbowałem dodać pojazd do mojego kontekstu, ale to połączyło tabele dla samochodu i moto w jeden stół pojazdu. Zdecydowanie chcę mieć osobny stolik na samochody i motory (a może także na stół dla właściwości bazowych pojazdu). Jaki jest najlepszy sposób na zrobienie tego?

+0

EF nie jest moją rzeczą, ale czy można uzyskać zestaw za pośrednictwem interfejsu, jeśli doda się go do kontekstu, np. zmienić "Pojazd" na "IVehicle"? – Eli

Odpowiedz

11

Posiadać właściwości pojazdu typu DBSet z Vehicle w klasie MyDbContext.

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

Teraz można uzyskać dostęp do wszystkich pojazdów z kryteriami jak to

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

Należy pamiętać, że trzeba mieć klucz obiekt, w swoich klasach jednostki (ID lub {ClassName}ID). W przeciwnym razie spowoduje to błąd czasu działania! (Tak kod zostanie skompilowany.)

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

EDIT: Zgodnie z komentarzem

domyślnie Entity Framework zrobi Tabela Per Hierarchii .Wszystkie dane w hierarchii są zapisywane w pojedynczym tabela i używa kolumny Discriminator do określenia, który rekord należy do podtypu. Tak więc w wyniku otrzymasz jedną tabelę pojazdów z kolumnami takimi samymi jak właściwości wszystkich twoich klas w hierarchii z dodatkową kolumną o nazwie "Discriminator". Dla rekordu dla samochodu, będzie mieć wartość "Samochód" w kolumnie Dyskryminatora.

enter image description here

Jeśli chcesz utworzyć jedną tabelę dla każdego typu, Pójdziemy do Tablicy od rodzaju. Entity Framework utworzy Tabelę dla klasy bazowej i oddzielną tabelę dla wszystkich klas potomnych.

Aby to się stało, możesz użyć Fluent API, aby nadpisać konfigurację.

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

     base.OnModelCreating(modelBuilder); 
    } 

a wyjście jest

enter image description here

Teraz powinno być możliwe do kwerendy wpisy pojazdów jak ten

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

a wynik jest tutaj

enter image description here

Należy zauważyć, że wynik zawiera zarówno typ MotorCycle, jak i typ Car.

Sprawdź to link, aby wybrać strategię dziedziczenia, której chcesz użyć.

+0

Prawidłowo. Zapomniałem w swoim przykładzie o rekwizyt id. –

+0

Wypróbowałem to i połączyłem moje samochody i motory w jeden stół, zwany pojazdem. Chcę tabeli według rodzaju. –

+0

@ByronSommardahl: Zobacz moją zaktualizowaną odpowiedź. – Shyju

0

Czy próbowałeś dać Vehicle swój własny kontekst za pomocą DBSet? Myślę, że może to zrobić dla ciebie.

+0

Zapytanie działa, gdy to robię, ale tabele są rozbijane na jeden. Przedtem była to tabela-za-typ ... nie jest to tabela-na-hierarchię. –

+0

Tak więc, aby było jasne, że masz VehicleDbContext i MyDbContext (z samochodami i moto), nadal tworzy on jedną tabelę o nazwie Vehicle? Czego używasz do tworzenia tabel? Czy próbowałeś używać nadpisywania EDMX, aby upewnić się, że dziedziczenie jest dokładnie takie, jak zaplanowałeś? –

0

Użycie wpisu DataAnnotation.Schema.Table ("TableName") na dziedziczonej klasie powoduje utworzenie nowej tabeli dla dziedziczonego typu (table-per-type) i eliminuje pole Discriminator w typie nadrzędnym tabela, bez potrzeby korzystania z kodu Fluent API.

Powiązane problemy