Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
EntityFramework: Laden von Teilobjekten
MeisterM
myCSharp.de - Member



Dabei seit:
Beiträge: 17

Themenstarter:

EntityFramework: Laden von Teilobjekten

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
pdelvo
myCSharp.de - Member

Avatar #avatar-3354.png


Dabei seit:
Beiträge: 1.346

beantworten | zitieren | melden

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
                   }
private Nachricht | Beiträge des Benutzers
MeisterM
myCSharp.de - Member



Dabei seit:
Beiträge: 17

Themenstarter:

beantworten | zitieren | melden

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:
Fehler
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?
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.482

beantworten | zitieren | melden

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?
private Nachricht | Beiträge des Benutzers
MeisterM
myCSharp.de - Member



Dabei seit:
Beiträge: 17

Themenstarter:

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.482

beantworten | zitieren | melden

a) schreibt man Variablen klein, damit man sie von Klassen und Methoden besser unterscheiden kann; ergo heißt es from einsatzmittelImEinsatz 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.
private Nachricht | Beiträge des Benutzers
MeisterM
myCSharp.de - Member



Dabei seit:
Beiträge: 17

Themenstarter:

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von MeisterM am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.482

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
MeisterM
myCSharp.de - Member



Dabei seit:
Beiträge: 17

Themenstarter:

beantworten | zitieren | melden

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
}                                                   };
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von MeisterM am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.482

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 6.778
Herkunft: Waidring

beantworten | zitieren | melden

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!"
private Nachricht | Beiträge des Benutzers