2016-05-15 14 views
2

Ich muss DB von Drittanbietern mit dem folgenden Schema unterstützen (sieht wie RoR-Stil aus?).Polymorphe Assoziation ohne Primärschlüssel in EF teilen

DB diagram

Hier ist Master-Tabelle Fahrzeug wo VehicleType ist ein Diskriminator (mögliche Werte sind 'Car' und 'Bike'). So im Fall VehicleType = 'Car' dann SubId Punkte zu verteilen, in Auto Tisch, wenn VehicleType = 'Bike' dann Datensätze Punkte Bike Tisch.

Und Plus-Tabellen teilen keine Primärschlüsselwerte.

Ich mag komplexe Logik in meinem Code zu vermeiden, aber ich kann nicht verstehen, wenn ich Vererbung hier verwenden kann (so Car : Vehicle und Bike : Vehicle) oder zumindest Navigationseigenschaft (so Car.Vehicle und Bike.Vehicle könnten funktionieren). Die Frage ist also, kann ich etwas davon verwenden? Wie implementiert man das?

+0

Wenn Sie das DB-Schema nicht ändern können, erstellen Sie nur 3 unabhängige Klassen ohne Vererbungsstrategie und Navigationseigenschaften wie 'Car.Vehicle', da sie nur im Fall von FKs möglich sind. –

+0

Dank @SlavaUtesinov, es scheint, dass Sie Recht haben. – Tony

Antwort

1

Tabellen keine Primärschlüssel teilen Werte

So gibt es keine Möglichkeit, dies zu einer Vererbungsschema abzubilden, die TPT hätte sein sollen. Die unterschiedlichen Primärschlüsselwerte verhindern dies.

Was übrig bleibt, ist die Zuordnung verschiedener Klassen, die miteinander verbunden sind, so dass Sie zumindest Navigationseigenschaften verwenden können, anstatt manuell nicht verbundene Entitäten zu verknüpfen. Ich habe einen Weg gefunden, dies zu tun, aber es ist nicht ideal. Eigentlich ist es ziemlich künstlich. Aber sehen Sie, ob es eine brauchbare Lösung für Sie ist.

benutzte ich diese Klassen:

public abstract class Vehicle 
{ 
    public int VehicleId { get; set; } 
    public string Name { get; set; } 
    public VehicleInfo VehicleInfo { get; set; } 
} 
public class CarVehicle : Vehicle 
{ } 
public class BikeVehicle : Vehicle 
{ } 

public abstract class VehicleInfo 
{ 
    public int ID { get; set; } 
} 
public class CarInfo : VehicleInfo 
{ 
    public string Model { get; set; } 
} 
public class BikeInfo : VehicleInfo 
{ 
    public bool IsEbike { get; set; } 
} 

I Tisch CarVehicle und BikeVehicle von TPHVehicle in den Einheiten aufgeteilt:

modelBuilder.Entity<Vehicle>().ToTable("Vehicle"); 
modelBuilder.Entity<Vehicle>() 
    .Map<CarVehicle>(m => m.Requires("VehicleType").HasValue("Car")) 
    .Map<BikeVehicle>(m => m.Requires("VehicleType").HasValue("Bike") 
     .HasColumnType("CHAR") 
     .HasMaxLength(4)); 

CarInfo und BikeInfo, auf der anderen Seite, müssen ihre eigenen haben Tabellen, also hier habe ich TPC:

verwendet

Und schließlich die Klassen verbindet:

modelBuilder.Entity<Vehicle>().HasRequired(c => c.VehicleInfo) 
    .WithOptional().Map(m => m.MapKey("SubId")); 

Durch den Basistyp VehicleInfo Verwendung es möglich ist, eine Eigenschaft Vehicle.VehicleInfo durch einen Fremdschlüssel SubId abzubilden. Es ist nicht möglich, dies zu haben:

public class CarVehicle : Vehicle 
{ 
    public CarInfo CarInfo { get; set; } 
} 
public class BikeVehicle : Vehicle 
{ 
    public BikeInfo BikeInfo { get; set; } 
} 

EF wird es nicht akzeptieren, wenn Sie versuchen, beide Navigationseigenschaften durch SubId abzubilden.

Der Hauptnachteil dieses Modells ist, dass Sie immer die "Info" Entitäten als VehicleInfo Objekte erhalten müssen.EF erstellt die richtigen Subtypen, aber ihr Kompilierungszeittyp ist VehicleInfo. Wenn Sie die VehicleInfo-Eigenschaft festlegen, müssen Sie ebenfalls daran denken, den richtigen Typ anzugeben. Sie können etwas, dass das Eigentum von einer Passthrough mildern ...

public class CarVehicle : Vehicle 
{ 
    [NotMapped] 
    public CarInfo CarInfo 
    { 
     get { return VehicleInfo as CarInfo; } 
     set { VehicleInfo = value; } 
    } 
} 

... und das gleiche in BikeVehicle. Sie können diese Eigenschaft jedoch nicht direkt in einer LINQ-Abfrage verwenden, da sie nicht zugeordnet ist (und nicht zugeordnet werden kann).

Ferner kann die ausgeführten SQL von etwas Einfachen wie ...

db.Set<CarVehicle>().Include(c => c.VehicleInfo).ToList(); 

... ist humongous wegen EF durch alle Vererbungs Bäume zu graben.

+0

Sie. Sind. Genuis! Das hilft viel :) – Tony

Verwandte Themen