2012-05-02 5 views
5

Ich habe folgende Typen:Querying von Basistyp in 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; } 
} 

Und ich habe einen Code-first DbContext:

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

Dies funktioniert gut, wenn ich für ein Auto abfragen oder moto direkt ...

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

Aber wenn ich eine Liste aller Fahrzeuge will, ob Auto oder moto, würde ich mag, dies zu tun:

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

Wenn ich den obigen Code versuchen, erhalte ich eine Ausnahme:

System.InvalidOperationException: Die Fahrzeuge Entitätstyp ist nicht Teil des Modells für den aktuellen Kontext.

Das macht Sinn ... Ich habe Fahrzeug nicht zum Kontext hinzugefügt. Ich habe Auto und Motorrad hinzugefügt. An diesem Punkt bin ich mir nicht sicher, was ich tun soll. Ich habe versucht, Fahrzeug zu meinem Kontext hinzuzufügen, aber das kombinierte die Tabellen für Auto und Motorrad in einen Fahrzeugtisch. Ich möchte auf jeden Fall einen separaten Tisch für Autos und Motorräder (und möglicherweise auch einen Tisch für die Fahrzeugbasis Eigenschaften). Was ist der beste Weg, dies zu tun?

+0

EF ist nicht mein Ding, aber könnten Sie über die Schnittstelle einen Satz bekommen, wenn Sie es zum Kontext hinzufügen, z. Wechsel von "Fahrzeug" zu "IVehicle"? – Eli

Antwort

11

Haben Sie eine Fahrzeugeigenschaft des Typs DBSet von Vehicle in Ihrer MyDbContext-Klasse.

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

Jetzt können Sie alle Fahrzeuge mit den Kriterien wie diese

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

Halten Sie zugreifen, die Sie eine Key-Eigenschaft in Ihrem Entitätsklassen haben sollten (ID oder {ClassName}ID). Sonst gibt es einen Laufzeitfehler! (Ja der Code kompilieren.)

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

EDIT: Gemäss Kommentar

von Standard Entity Framework wird in der Hierarchie eine Tabelle pro Hierarchie .Alle Daten tun wird in einem einzigen gespeichert Tabelle und verwenden Sie die Spalte Discriminator, um zu ermitteln, welcher Datensatz zu welchem ​​Subtyp gehört. Als Ergebnis erhalten Sie eine Vehicle-Tabelle mit den gleichen Spalten wie die Eigenschaften All Ihrer Klassen in der Hierarchie mit einer zusätzlichen Spalte namens "Discriminator". Für einen Rekord für das Auto, wird es den "Car" -Wert innerhalb der Diskriminator-Spalte haben.

enter image description here

Wenn Sie für jede Art Einzel Tabelle erstellen möchten, sind wir für Tabelle pro Typ gehen. Entity Framework erstellt eine Tabelle für die Basisklasse und eine separate Tabelle für alle untergeordneten Klassen.

Um dies zu erreichen, können Sie die Fluent API verwenden, um die Konfiguration zu überschreiben.

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

     base.OnModelCreating(modelBuilder); 
    } 

Und der Ausgang ist

enter image description here

Jetzt sollten Sie in der Lage sein, Ihr Fahrzeug Einträge wie diese

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

abzufragen Und das Ergebnis ist hier

enter image description here

Beachten Sie, dass das Ergebnis sowohl den Typ MotorCycle als auch den Typ Car enthält.

Aktivieren Sie diese Option link, um zu entscheiden, welche Vererbungsstrategie verwendet werden soll.

+0

Korrekt. Ich habe vergessen, die ID-Prop in meinem Beispiel aufzunehmen. –

+0

Versuchte dies und es kombinierte meine Autos und Motorräder in einen Tisch namens Fahrzeuge. Ich möchte eine Tabelle pro Typ. –

+0

@ByronSommardahl: Siehe meine aktualisierte Antwort. – Shyju

0

Haben Sie versucht, Fahrzeug mit einem DBSet seinen eigenen Kontext zu geben? Ich denke, das könnte es für dich tun.

+0

Die Abfrage funktioniert, wenn ich dies tue, aber die Tabellen werden in einen zusammengeschlagen. Bevor es Tabelle-pro-Typ war ... ist es nicht Tabelle für Hierarchie. –

+0

Also nur um klar zu sein, haben Sie einen VehicleDbContext und einen MyDbContext (mit Autos und Moto) erstellt es immer noch eine Tabelle namens Vehicle? Was verwenden Sie zum Erstellen der Tabellen? Haben Sie auch versucht, den EDMX-Writer darüber zu verwenden, um sicherzustellen, dass die Erbschaft genau so ist, wie Sie es geplant haben? –

0

Mit einem DataAnnotation.Schema.Table-Eintrag ("TableName") für die geerbte Klasse wird die Erstellung einer neuen Tabelle für den geerbten Typ (Tabelle-pro-Typ) ausgelöst und das Feld "Diskriminator" im übergeordneten Typ entfernt Tabelle, ohne den Fluent-API-Code zu benötigen.

Verwandte Themen