Laden...

EntityFramework: Laden von Teilobjekten

Erstellt von MeisterM vor 11 Jahren Letzter Beitrag vor 11 Jahren 4.169 Views
M
MeisterM Themenstarter:in
17 Beiträge seit 2012
vor 11 Jahren
EntityFramework: Laden von Teilobjekten

verwendetes Datenbanksystem: PostgreSQL 9.1

Hi Leute,

ich verwendet EntityFramework 4.1 und stehe nun vor einem "Problem": Ich lade die Objekte und verschicke Sie mit WCF an den Client. Nun habe ich recht Komplexe Objekte mit vielen Verknüpfungen. Von denen ich aber nur eine Teilmenge an Eigenschaften bei der Übertragung benötige.

Wie kann ich es realisieren, nur bestimmte Eigenschaften zu laden. Oder muss ich dafür neue Objekte anlegen die auf die gleichen Felder gemappt sind? Ich benutze das Model-First Prinzip.

Gruß
Holger

1.346 Beiträge seit 2008
vor 11 Jahren

Du kannst doch mit Linq bestimmen welche Dinge du laden willst

So kannst du zB nur Name und Addresse laden. Soeit ich weiss wird auch dann auch nur Name und Adresse im resultierenden SQL Query eingebaut und der Rest nicht.


var results = from TableEntity x in table
                   where .....
                   select new TableEntity
                   {
                       Name = x.Name,
                       Address = x.Address
                   }

M
MeisterM Themenstarter:in
17 Beiträge seit 2012
vor 11 Jahren

Das wäre natürlich die super Lösung. Allerdings erhalte ich bei folgendem Code:


            IQueryable<EinsatzmittelImEinsatz> x = from EinsatzmittelImEinsatz c in REVServer.Env.DBContext.EinsatzmittelImEinsatzMenge
                                                   where c.Einsatz.ID == EinsatzID
                                                   select new EinsatzmittelImEinsatz{
                                                       ID = c.ID ,
                                                       ZeitAlarm = c.ZeitAlarm,
                                                       ZeitDispo = c.ZeitDispo,
                                                   
                                                       StatusZeit = c.StatusZeit
                                                   };

            return x.ToList<EinsatzmittelImEinsatz>();

Kommt die folgende Meldung:

Fehlermeldung:
Die Entität bzw. der komplexe Typ 'DataModel.EinsatzmittelImEinsatz' kann nicht in einer 'LINQ to Entities'-Abfrage konstruiert werden.

Eine Idee? Muss noch etwas eingestellt werden?

16.806 Beiträge seit 2008
vor 11 Jahren

Versuchst Du eine ExtensionMethod zu schreiben, oder wie bettest Du die Methoden hier ein, dass die Fehlermeldung kommt?
Wird sie erst bei der Ausführung geworfen?

M
MeisterM Themenstarter:in
17 Beiträge seit 2012
vor 11 Jahren

Nein ich schreibe keine Extension Method, sondern führe einfach die Methode aus um die Objekte dafür zu erhalten.

        public List<EinsatzmittelImEinsatz> Einsatz_GetEinsatzmittel(Int64 EinsatzID)
        {
            IQueryable<EinsatzmittelImEinsatz> x = from EinsatzmittelImEinsatz c in REVServer.Env.DBContext.EinsatzmittelImEinsatzMenge
                                                   where c.Einsatz.ID == EinsatzID
                                                   select new EinsatzmittelImEinsatz{
                                                       ID = c.ID ,
                                                       ZeitAlarm = c.ZeitAlarm,
                                                       ZeitDispo = c.ZeitDispo,                                                       
                                                       StatusZeit = c.StatusZeit
                                                   };

            return x.ToList<EinsatzmittelImEinsatz>();
        }

Die Fehlermeldung wird erst zur Ausführzeit geworfen.

16.806 Beiträge seit 2008
vor 11 Jahren

a) schreibt man Variablen klein, damit man sie von Klassen und Methoden besser unterscheiden kann; ergo heißt es ~~ from ++e++insatzmittelImEinsatz und~~ einsatzID statt EinsatzID.
Ist zwar jedem freigestellt, dass er das machen kann wie er will - darüber muss man auch nicht diskutieren - sondern es einfach akzeptieren.

b) ist EinsatzmittelImEinsatz ist offensichtlich Deine Entity. Da Du hier eine Projektion von Daten erreichen willst, also das Selektieren von bestimmten Spalten, musst Du Dir eine Klasse bauen, die GENAU die Properties enthält, die Du haben willst.
Das Verwenden von Entities bei Projektionen ist falsch und ergibt genau diesen Fehler.

c) da Du offensichtlich Methoden gesammelt in einer Schnittstelle ertellen willst, schau Dir Repositories an. Idealerweise ein Generic Repository mit UnitOfWork-Pattern würde sich anbieten bzw. ist empfohlen.
Ich sag eins gleich vorweg: Projektion von Daten kann man, macht man aber prinzipiell in Repositories nicht; bzw nur in gekapselten Repositories. Hierzu eigenen sich wie gesagt dann Projektions-Klassen als Repository.

M
MeisterM Themenstarter:in
17 Beiträge seit 2012
vor 11 Jahren

Ja das ist ja wunderbar.

Laut dem vorherigen Post sollte TableEntity als Klasse sowohl für die "neue" Klasse als auch als Typenidentifier für die zu lesende Entity verwendet werden, daher habe ich das in meinem Beispiel auch so gemacht. Entsprechend war dies dann eine Klasse und keine Variable.

Kann ich mir auch eine Klasse bauen die eine Liste von Unterklassen enthält die wieder rum mit Daten aus der Entity gefüllt werden?

PS: Ziel des ganzen ist es, den Traffic der durch den Transfer der Entity Klassen über WCF generiert wird zu minimieren.

Problematisch sind hier dann nämlich DataEntities die wiederrum Verweise auf große andere Entities enthalten. Diese würde ich dann gerne einfach beim Abrufen ausschließen.

Habe nun herausgefunden, dass man LazyLoading deaktivieren muss und dann kann man per Hand bestimmen welche Abhängigkeiten mit geladen werden.

16.806 Beiträge seit 2008
vor 11 Jahren

Ich hab keine Ahnung, was Du nun mit dem Beitrag aussagen willst.

Wenn Du eine Web-API für Dritte entwickelst, dann solltest Du auch wirklich nur die Daten liefern, die der Entwickler anfragt.
Und ganz wichtig: Versionierung der API!

Hier eine bestehende Entity, vielleicht sogar mit Standardwerten zurück zu geben, ist ein ganz schlechter Stil und sicherlich keine saubere Lösung; auch wenn Du das Ziel vom Laden nur bestehender Werte aus der DB erreichst.
Wie gesagt; Standardwerte werden so auch serialisiert - selbstverständlich unerwünscht und womöglich auch falsch.

Mehr als Dir sagen, dass man sich dafür bestimmte Klassen bastelt, kann ich nicht. Wie die Klassen aussehen kannst Du natürlich selbst bestimmen. Kannst jetzt als Rat annehmen oder nicht.

M
MeisterM Themenstarter:in
17 Beiträge seit 2012
vor 11 Jahren

Alles klar. Und wie kann ich die selbst gebastelten Klassen wieder zurück führen in ein Entity Objekt um die neuen Werte zu speichern? Oder muss ich dass dann mit einem eigenen Mapper wieder zurück führen und eine entsprechende Add, Update, Remove Funktionalität einbauen und habe somit die Vorteile von EF wieder verspielt?

Es geht nicht um eine WebAPI sondern um eine WCF TCPBinding Verbindung zwischen meinem eigenen Server und meinem eigenen Client.

Die Frage war jetzt wenn ich eigene Klassen verwendee kann ich ja wohl mit

IQueryable<EmittelEinsatz> x = from c in REVServer.Env.DBContext.EinsatzmittelImEinsatzMenge
                                                   where c.Einsatz.ID == EinsatzID
                                                   select new EmittelEinsatz {
                                                       ID = c.ID ,
                                                       ZeitAlarm = c.ZeitAlarm,
                                                       ZeitDispo = c.ZeitDispo                                                   };

´
ein Objekt vom Typ EMittelEinsatz direkt mit den Werten befüllen. Nun besteht aber die Entity EinsatzmittelImEinsatz noch aus einem weiteren Feld StatusZeit. Dies ist ein Array von weiteren Entities. Wie kann ich nun dieses Array in eine weitere, extra dafür angelegte Klasse füllen?

Also irgendwie etwas wie:

select new EmittelEinsatz {
                                                       ID = c.ID ,
                                                       ZeitAlarm = c.ZeitAlarm,
                                                       ZeitDispo = c.ZeitDispo,
StatusZeit[] = new StatusZeiten {
Zeit = c.StatusZeit.Zeit,
Manuell = c.StatusZeit.Manuell
}                                                   };

16.806 Beiträge seit 2008
vor 11 Jahren

Natürlich musst Du das Mapping von einem ViewModel auf die Entity selbst übernehmen. Wie solls denn automatisch funktionieren? Gibt ja keine logische Verbindung......

Naja Du hast hier falsche Vorstellungen; offensichtlich hast Du Dich nicht ausreichend damit beschäftigt.
Du kannst auch die POCOs durch den WCF schieben, sodass der Client nur genau das lädt, was er braucht. Wenn Du das manuell machen willst - in der Schnittstelle - musst Dich halt um alles selbst kümmern.

Gibt aber wirklich genug Tutorials, wie man das EF und das WCF für verschiedene Zwecke optimal nutzt.

Wie man Daten von Klasse A auf Klasse B überträgt, muss ich Dir hoffentlich nicht erklären. Und das Programmieren werd ich Dir auch nicht übernehmen. Vielleicht beschäftigst Dich damit einfach ein wenig, und probierst ein paar Dinge aus und verwendest dann das, was am besten passt? Wie gesagt; gibt genug Tutorials.

Siehe auch [Hinweis] Wie poste ich richtig? 1.1 und 4c

6.911 Beiträge seit 2009
vor 11 Jahren

Hallo MeisterM ,

so wie ich das sehe suchst du "Table Splitting".

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"