Laden...

EF: Fremdschlüsselkomponente in vererbten Typ nicht vorhanden

Erstellt von toxic vor 6 Jahren Letzter Beitrag vor 6 Jahren 2.520 Views
T
toxic Themenstarter:in
64 Beiträge seit 2010
vor 6 Jahren
EF: Fremdschlüsselkomponente in vererbten Typ nicht vorhanden

verwendetes Datenbanksystem: LocalDB

Hi,

ich versuche folgendes Modell per Code First aufzubauen.
Bei der Generierung bekomme ich folgende Fehlermeldung:

Fehlermeldung:
Die Fremdschlüsselkomponente 'AutoID' ist keine für den Typ 'Kombiaenderungsstand' deklarierte Eigenschaft. Vergewissern Sie sich, dass sie nicht explizit aus dem Modell ausgeschlossen wurde und dass es sich um eine gültige primitive Eigenschaft handelt.

Zum einen hat er ja recht, der "Kombiaenderungsstand" hat keine AutoID. Aber müsste er diese nicht per Vererbung mitbekommen? Wie könnte ich das lösen?
Muss ich wirklich unter "Kombi" eine Liste mit "Autoaenderungsstaende" hängen?

Oder liegt das an TPT, geht das dann nicht?


using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WPMS2_EF_Test
{
    public class AutoContext : DbContext
    {
        public DbSet<Kombi> Kombis { get; set; }
        public DbSet<SUV> SUVs { get; set; }
        public DbSet<Kombiaenderungsstand> Kombiaenderungsstaende { get; set; }
        public DbSet<SUVaenderungsstand> SUVaenderungsstaende { get; set; }

        public AutoContext() : base()
        {

        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Auto>().ToTable("Autos");
            modelBuilder.Entity<Kombi>().ToTable("Kombis");
            modelBuilder.Entity<SUV>().ToTable("SUVs");
            modelBuilder.Entity<Autoaenderungsstand>().ToTable("Autoaenderungsstaende");
            modelBuilder.Entity<Kombiaenderungsstand>().ToTable("Kombiaenerungsstaende");
            modelBuilder.Entity<SUVaenderungsstand>().ToTable("SUVaenderungsstaende");

            modelBuilder.Entity<Kombi>()
                .HasMany<Kombiaenderungsstand>(x => x.Kombiaenderungstaende)
                .WithRequired()
                .HasForeignKey(x => x.AutoID);

            modelBuilder.Entity<SUV>()
                .HasMany<SUVaenderungsstand>(x => x.SUVaenderungstaende)
                .WithRequired()
                .HasForeignKey(x => x.AutoID);
        }

        public abstract class Auto
        {
            public virtual int AutoID { get; set; }
            public ICollection<Autoaenderungsstand> Autoaenderungstaende { get; set; }
        }

        public class Kombi : Auto
        {
            public ICollection<Kombiaenderungsstand> Kombiaenderungstaende { get; set; }
        }

        public class SUV : Auto
        {
            public ICollection<SUVaenderungsstand> SUVaenderungstaende { get; set; }
        }



        public abstract class Autoaenderungsstand
        {
            public virtual int AutoaenderungsstandID { get; set; }
            public virtual int AutoID { get; set; }
        }

        public class Kombiaenderungsstand : Autoaenderungsstand
        {

        }

        public class SUVaenderungsstand : Autoaenderungsstand
        {

        }
    }

}


W
955 Beiträge seit 2010
vor 6 Jahren

Hi,

  1. Navigation im EF ist immer bidirektional.
  2. Denke daran dass es sowas wie Kovarianz gibt.
16.807 Beiträge seit 2008
vor 6 Jahren

Eine Klasse abstract zu deklarieren und sie dann als Entität im EF Context nutzen: macht kein Sinn und wird sehr wahrscheinlich auch krachen.

Für mich macht aber das ganze Schema keinen Sinn.
Ist das wirklich so gewollt - und durchdacht?

Ob ein Fahrzeug ein Kombi oder ein SUV ist, ist ja normalerweise nichts anderes als eine Eigenschaft - und keine neue Entität.

T
toxic Themenstarter:in
64 Beiträge seit 2010
vor 6 Jahren

Ja das Datenmodell ist so gewollt.
Das ganze dient ja hier nur zu Veranschaulichung.

Bei uns gibt es verschiedene Produkte (diese haben verschiedene Eigenschaften und auch gemeinsame) und die Produkte sollen Änderungsstände haben (diese haben auch verschiedene Eigenschaften und auch gemeinsame)

Ist in einem PLM-System (z.B. Teamcenter von Siemens eine ganz normale gänige Praxis)

Das die abstracten-Klassen aus dem Context rauszunehmen sind, macht Sinn und ist auch klar.

Aber das ändert ja nichts an meinem Problem.

Wieso findet EF die "AutoID" nicht, sie wird doch mitvererbt...das ist für mich eigentlich die Frage.
Die Kombis und SUVs haben doch auch in der Tabelle die "AutoID" als PrimaryKey und als Foreign Key zur Tabelle "Autos". Oder nicht?

@Abt, das mit TPT hast du gelessen? Dann kann ich doch die Eigenschaften von dieser Vererbungsebene in eine gemeinsame Tabelle schreiben "Autos".

Siehe hier https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-tpt und Zitat von http://www.entityframeworktutorial.net/code-first/inheritance-strategy-in-code-first.aspx

Table per Hierarchy (TPH): This approach suggests one table for the entire class inheritance hierarchy. Table includes discriminator column which distinguishes between inheritance classes. This is a default inheritance mapping strategy in Entity Framework.
Table per Type (TPT): This approach suggests a separate table for each domain class.
Table per Concrete class (TPC): This approach suggests one table for one concrete class, but not for the abstract class. So, if you inherit the abstract class in multiple concrete classes, then the properties of the abstract class will be part of each table of the concrete class.

16.807 Beiträge seit 2008
vor 6 Jahren

Klar hab ich das gelesen; aber es ist nicht selten, dass die Leute solch ein Design aus Versehen machen und sich damit nen Grab schaufeln 😉

Sieht aber aus, dass das so per design nicht gewollt ist:
Keys in CLR Abstract Base Class Broken #6087

T
toxic Themenstarter:in
64 Beiträge seit 2010
vor 6 Jahren

Hi,

also ich hab euch noch mal ein Klassendiagramm angehängt. So stell ich mir das Ganze vor.
Nach meiner Meinung macht das Modell eigentlich schon so Sinn. (Sonst hätte auch alle PLM System einen falschen Ansatz 😉 )

Wie würdet ihr das dann im EF abbilden?

D
985 Beiträge seit 2014
vor 6 Jahren

Du willst jetzt also ernsthaft für jedes Produkt eine eigene Klasse definieren?

Wie muss ich mir das dann in der Produktiv-Umgebung vorstellen, wenn ein neues Produkt erstellt werden soll? Soll das dann Aufgabe der Entwicklungsabteilung sein (Anwendung erweitern, Testen, Rollout)?

Selbst wenn man EF ausser acht lässt, sieht man, dass das Konzept schon im Ansatz nicht richtig sein kann.

T
toxic Themenstarter:in
64 Beiträge seit 2010
vor 6 Jahren

Nicht für jedes Produkt, aber es gibt bei uns 4 Produktbereiche.
Diese möchte ich abbilden.

Falls wir ein Hersteller von Autos und Motorräder währen, würde ich eine Klasse Fahrzeug, ein Auto und Motorrad machen. Diese haben wiederum Änderungsstände.

So falsch kann das doch nicht sein oder? Ein Auto hat doch ganz andere Eigenschaften wie ein Motorrad, aber eben auch gleiche...

16.807 Beiträge seit 2008
vor 6 Jahren

Sonst hätte auch alle PLM System einen falschen Ansatz 😉

Ich wage zu bezweifeln, dass man PLM Systeme heute so umsetzt, wie vor 30 Jahren....

SAP macht das vor: sie gehen weg von relationalen DB Systemen. Amazon, Facebook... keiner entwickelt PLM Systeme mehr so.

Wäre für mich daher auch ein perfektes Beispiel für eine NoSQL Datenhalde.

In Vorträgen über NoSQL verwende ich zwar keine Autos sondern Produkte des täglichen Bedarfs - um Publikumsneutral zu sein - aber der Sinn ist identisch:
> Produkte haben grundsätzliche gleiche Eigenschaften (Name, Hersteller, EAN); aber dann auch spezifische (Inhaltsstoffe, Herkunftspflichten...).

Hab auch schon ein PLM-System für einen bekannten Kettensägenhersteller designed... das sieht nicht so aus.

D
985 Beiträge seit 2014
vor 6 Jahren

Und wenn ich sowas umsetzen müsste, dann würde es für mich nur Produkte geben.

Dazu noch Templates für neue Produkte (wie z.B. Auto-Template, Motorrad-Template, Kettensägen-Template ...) um nicht bei jedem bei Null anfangen zu müssen.