Mapping mit Linq-Abfrage-Ergebnisse zu einer DTO-Klasse
Möchte ich, um Datensätze aus der Datenbank mit EF und weisen Sie die Werte zu einer DTO-Klasse.Betrachten Sie die folgenden Tabellen für eine Linq-Abfrage.
TableA,TableB, TableC
Für jede Tabelle a ein Datensatz, mehrere Datensätze in Tabelle B. Für jede Tabelle B Datensatz, mehrere Datensätze in TableC.
Nun meine DTOs Aussehen
public class TableA_DTO
{
public int tableA_rowid { get; set; }
//remaining tableA field definitions
public List<TableB_DTO> TableB_records { get; set; }
}
public class TableB_DTO
{
public int tableB_rowid { get; set; }
//remaining tableB field definitions
public List<TableC_DTO> TableC_records { get; set; }
}
public class TableC_DTO
{
public int tableC_rowid { get; set; }
//remaining tableC field definitions
}
meine linq-Abfrage wie folgt aussieht
var qry = from ent in TableA
select ent;
In meinem mapping-Klasse-I-Schleife durch die Elemente in Abfrage-Ergebnis so:
foreach (var dataitem in query)
{
TableA_DTO dto = new TableA_DTO();
dto.tableA_rowid = dataitem.ID;
//remaining field definitions here
}
Nun, das funktioniert für alle Felder in TableA wo holt sich einen Datensatz aus der Datenbank und legt die benötigten Eigenschaften in TableA_DTO für jedes Feld in der Tabelle TableA. Ich möchte auch Auffüllen, alle übereinstimmenden Datensätze in Tabelle B in der Tabelle a-Eigenschaft-Feld durch den Namen TableB_records und auch in TableB_DTO alle übereinstimmenden Datensätze aus TableC in TableB_DTO Eigentums durch den Namen TableC_records
Kann das getan werden? Was muss ich ändern? Ist es die linq-Abfrage oder die Art, wie ich mein mapping
Vielen Dank für Ihre Zeit...
- Gibt es einen Grund, dass man nicht mit Entity Framework POCO ' s (aka DbContext, manchmal falsch genannt Ersten Code)? Im Grunde, können Sie beseitigen die Notwendigkeit für DTO und Nutzung EF POCO ' s statt?
- Haben Sie sich überlegt mit AutoMapper ? Je nachdem, wie andere Ihre DTOs sind, dies könnte so einfach wie zwei oder drei Zeilen code für das mapping.
- Die Datenbank ist bereits vorhanden, so ging die edmx-Weg
- ich würde nicht noch etwas ändern müssen in der linq-Abfrage, um die Daten an, so kann automapper verwenden? Es sieht nicht wie automapper tun können, dass aus meiner übersicht..es wird tiefer Graben, wenn Sie sagen, es tut... danke 🙂
- Sie würde immer noch mit den EF-Objekte zu erhalten Ihre Daten. AuotMapper Karte würde dann die relevanten Felder von einem zum anderen (und zurück). Wenn Sie es tun, durch Konvention (z.B. gleiche Namen), BIN wie Magie funktioniert. Wenn Sie Präfixe, die in Ihrem DTO, können Sie selbst definieren.
- Aber haben Sie POCO ist? Ich sage "code first", denn das ist es, was viele Menschen rufen Sie es, aber Sie können gehen Sie die edmx-route, und trotzdem poco/dbcontext-statt Objekt-Kontext (Sie Haken einen anderen T4 auf der Modell-Diagramm). Das gibt Sie Ihrer leichten POCO, aber Sie sind immer noch Modell - oder Datenbank - ersten.
- Ich erstellte DTO-Klassen, also konnte ich die Werte aus der edmx-Klassen und weisen Sie diese auf meinem getrennt geringes Gewicht DTO-Klassen mit einem mapper, die ich zu schreiben, das für jedes DTO. Der automapper würde haben dieses problem gelöst. Aber die akzeptierte Antwort hier unten, entfernt die Notwendigkeit an der auto-Karte, denn jetzt ist meine var query ist vom Typ {myCustomDTO}
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich würde ändern Sie Ihre DTO aus
List
zuIEnumerable
und als alles in eine LINQ-Abfrage.N + 1
Abfragen; es löstM * (N + 1) + 1
Abfragen mit ziemlicher Sicherheit dazu führen, dass sehr schlechte Leistung.TableB_records
undTableV_records
Eigenschaften. Schauen Sie genau auf, die einzelne Abfrage, die ausgeführt wird, mithilfe von SQL profiler. Sie werden bemerken, dass es fehlt, alle Informationen überTableB
undTableC
.Erste, was, ich muss nur Fragen, ob Sie Entity Framework 4.1 und POCOs (DbContext) und vermeiden Sie die Notwendigkeit für DTO ist altoghther?
Unter der Annahme, dass die Antwort Nein ist, werden müssen, weil Sie nicht ziehen wieder alle Felder, oder Sie sind irgendwie die änderung der "Form" der Daten.
In diesem Fall könnten Sie ändern Ihre LINQ-Abfrage wie folgt Aussehen:
Den Vorteil, es zu tun auf diese Weise: Wenn Sie SQL Profiler, Sie sollten sehen, dass nur die Spalten, die Sie anfordern, machen Sie es in die eigentliche SQL-Abfrage. Wenn Sie die Abfrage es werden alle ersten und ziehen Sie dann die Werte, all die Säulen werden abgerissen, der Draht.
Ich würde einen factory-Methode, dh:
TableA_DTO CreateDTO(TableAItem item);
Nutzung dieser, können Sie einfach schreiben Sie Ihre Abfrage wie:
Dies würde Ihnen die Kollektion von "DTO" - Objekte direkt.
That being said, wenn Sie mithilfe von Entity Framework, die EF Code First Hinzugefügt, die in den letzten Versionen könnten jedoch nützlich sein, in diesem Fall.
AsEnumerable()
auf eineIQueryable<T>
wird sichergestellt, dass Sie nach unten ziehen, werden alle Zeilen aus der Datenbank. Es sei denn, die Tabelle hat weniger als tausend Zeilen (und alle Ihre Daten), oder es sei denn, Sie wollten alle Datensätze sowieso sehr schlecht für die performance.UPDATE
Als andere darauf hingewiesen, Abflachung der Ergebnisse (siehe unten) ist nicht erforderlich bei der Arbeit mit Entity Framework 4.0, da kann es dann übersetzen Sie die LINQ-Abfrage, um eine effiziente abgeflacht Ergebnis für Sie. Also, der folgende code ist nur erforderlich bei der Arbeit mit LINQ to SQL (und möglicherweise noch weitere LINQ-Anbieter). Beachten Sie, dass ich habe nur diese getestet mit EF über SQL Server und nicht über Orakel, da dieses Verhalten könnte sein, LINQ provider-spezifisch, was bedeutet, dass die Oracle-provider (noch in beta) oder das kommerzielle Red Lizard-provider für Oracle könnte noch tun, N + 1.
, Was Sie versuchen zu tun ist, um eine Menge von Objekten, die aufgebaut sind wie ein Baum. Ohne Besondere Pflege, Sie werden auslösen viele Abfragen an die Datenbank. Mit einer Verschachtelungsebene, die Sie hätte auslösen N + 1 Abfragen, aber da Ihre Verschachtelung ist zwei Ebenen tiefer, werden Sie auslösen M x (N + 1) + 1 Anfragen, die werden sicherlich sehr schlecht für die performance (egal, was die Größe des Datensatzes ist). Was Sie wollen ist, um sicherzustellen, dass es nur eine einzige Abfrage an die Datenbank gesendet. Um dies zu gewährleisten, müssen Sie erstellen Sie eine temporäre Abfrage, flacht sich das Ergebnis, wie Sie es getan haben, in der guten alten SQL-Tage abrufen, die Baum-Daten :-).werfen Sie einen Blick auf das folgende Beispiel:Der nächste Schritt ist, zu transformieren, die in-memory-Daten-Struktur (Verwendung anonymer Typ) in die Baumstruktur des DTO-Objekte:
Wie Sie sehen können, der erste Teil der Lösung ist tatsächlich die 'alte' Art und Weise, dies zu tun, Weg zurück, wenn wir noch schreiben, die SQL-Abfragen per hand. Schön ist jedoch, dass sobald wir diese typisierte Reihe von in-memory-Daten, die wir nutzen können, LINQ (to Objects) erneut, um diese Daten in die Struktur, die wir wollen.
Beachten Sie, dass dies können Sie auch tun, paging und Sortieren. Das wird ein wenig komplizierter, aber sicherlich nicht unmöglich.