Hat AutoMapper Unterstützung von Linq?
Ich bin sehr interessiert in Linq to SQL mit Lazy load-Funktion. Und in meinem Projekt, das ich verwendet AutoMapper zu map-DB-Modell Domänen-Modell (aus DB_RoleInfo
zu DO_RoleInfo
). In meinem code-repository wie unten:
public DO_RoleInfo SelectByKey(Guid Key)
{
return SelectAll().Where(x => x.Id == Key).SingleOrDefault();
}
public IQueryable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
SelectAll
Methode gut laufen, aber wenn ich Anrufe SelectByKey
bekomme ich den Fehler:
Methode “RealMVC.Daten.DO_RoleInfo MapDB_RoleInfo,DO_RoleInfo" nicht übersetzen konnte, um SQL.
Ist es, dass Automapper nicht unterstützt Linq komplett?
Statt Automapper, versuchte ich die manuelle mapping-code unten:
public IQueryable<DO_RoleInfo> SelectAll()
{
return from role in _ctx.DB_RoleInfo
select new DO_RoleInfo
{
Id = role.id,
name = role.name,
code = role.code
};
}
Diese Methode funktioniert, wie ich es mir vorstelle.
- Nur ein Hinweis auf das update in Ergänzung zu meiner Antwort: Die zweite version funktioniert, weil Linq to SQL, die bereits weiß, dass Sie getan haben, eine irreversible Projektion; die
SelectByKey
ist eigentlich nur mithilfe von Linq to Objects. Wenn Sie untersuchen die tatsächliche Abfrage, die generiert wird, ich glaube, Sie werden feststellen, dass es immer noch die Auswahl aller Entitäten aus der Datenbank, die entsprichtToList()
und dann filtern Sie die Ergebnisliste. - Es ist nicht so, dass AutoMapper unterstützt LINQ. Es ist, dass LINQ to SQL nicht unterstützt AutoMapper. Das LINQ zum SQL-Abfrage-Anbieter blickt auf die expression tree zu bestimmen, wie zu generieren der SQL-Abfrage. Wenn es um den Mapper.Karte Stück, es hat keine Ahnung, wie zu generieren der SQL.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Während @Aaronaught die Antwort richtig war, zu der Zeit des Schreibens, wie oft die Welt hat sich verändert und AutoMapper mit ihm. In der Zwischenzeit,
QueryableExtensions
wurden Hinzugefügt, um die code-Basis, die Unterstützung für die Projektionen, die übersetzt in Ausdrücke und, schließlich, SQL.Die core-extension-Methode ist
ProjectTo
1. Dies ist, was Ihr code könnte wie folgt Aussehen:und es würde sich Verhalten, wie die manuelle Zuordnung. (Die
CreateMap
Erklärung ist hier zu Demonstrationszwecken. Normalerweise würden Sie mappings definieren einmal beim Start der Anwendung).So, dass nur die Spalten, die erforderlich sind für die Zuordnung abgefragt werden und das Ergebnis ist ein
IQueryable
, der hat immer noch die original-query-provider (linq-to-sql, linq-to-entities, was auch immer). So ist es immer noch zusammensetzbar und das übersetzen in eineWHERE
- Klausel in SQL:1
Project().To<T>()
vor v. 4.1.0SelectAll().SingleOrDefault(x => x.Id == Key);
Ändern Sie Ihre zweite Funktion dieser:
AutoMapper funktioniert gut mit Linq to SQL, aber es kann nicht ausgeführt werden, da ein Teil der latenten Abfrage. Hinzufügen
ToList()
am Ende der Linq-Abfrage bewirkt, dass es sofort die Ergebnisse zu bewerten, anstatt zu versuchen zu übersetzen, die AutoMapper-segment als Teil der Abfrage.Klärung
Den Begriff der die verzögerte Ausführung (nicht "lazy load") macht keinen Sinn, sobald Sie geändert haben, auch die daraus resultierende Art zu etwas, dass nicht eine Entität Daten. Betrachten Sie diese zwei-Klassen:
Betrachten Sie jetzt die folgende Abbildung:
Diese Zuordnung ist völlig in Ordnung (es sei denn, ich habe einen Tippfehler gemacht), aber lassen Sie uns sagen, Sie schreiben die
SelectAll
- Methode in Ihrer ursprünglichen post, anstatt meine berichtigte Fassung:Dies tatsächlich funktioniert, aber durch den Aufruf selbst ein "queryable", es liegt. Was passiert, wenn ich versuche, dies zu schreiben, dagegen:
Denken wirklich hart über diese. Wie könnte Linq to SQL möglicherweise in der Lage, erfolgreich verwandeln Sie Ihre
where
in eine tatsächliche Datenbank-Abfrage?Linq weiß nichts über die
DO_RoleInfo
Klasse. Es weiß nicht, wie zu tun, die Zuordnung rückwärts - in einigen Fällen, dass die vielleicht gar nicht möglich. Sicher, man kann sich bei diesem code und gehen Sie "Oh, das ist einfach, suchen Sie einfach nach 'Administrator' oder 'Executive' in denName
Spalte", aber du bist der einzige, der weiß, dass. Soweit Linq to SQL betroffen ist die Abfrage ist purer Unsinn.Vorstellen, dass jemand hat Sie diese Anweisungen:
Es sei denn, Sie haben es geschafft, bevor, und die meisten Menschen nicht, Ihre Antwort auf, dass der Unterricht am ehesten zu sein:
Können Sie auf den Markt gehen, und Sie können bestimmte Bestandteile von Namen, aber Sie können nicht den Zustand bewerten, ich habe Ihnen , während Sie dort sind. Ich habe zu "un-Karte" die Kriterien ersten. Ich muss Ihnen sagen, hier sind die Zutaten, die wir brauchen für das Rezept - jetzt gehen und Sie Holen.
Zusammen zu fassen, das ist keine einfache Inkompatibilität zwischen Linq to SQL und AutoMapper. Es ist nicht eindeutig auf eine der beiden Bibliotheken. Es spielt keine Rolle wie Sie tatsächlich tun, die Zuordnung zu einem nicht-entity-Typ - Sie könnte genauso gut tun, die Zuordnung manuell, und Sie würden immer noch die gleichen Fehler, weil Sie geben jetzt Linq to SQL eine Reihe von Anweisungen, die nicht mehr nachvollziehbar, die sich mit mysteriösen Klassen, die nicht über eine systeminterne Zuordnung zu einem bestimmten entity-Typ.
Dieses Problem ist grundlegend für das Konzept des O/R-Mapping und deferred query-Ausführung. Ein Projektion ist ein one-way-operation. Sobald Sie das Projekt, Sie kann nicht mehr zurück, um die Abfrage-engine und sagen ach übrigens, hier sind noch einige weitere Bedingungen, die für Sie. Es ist zu spät. Das beste, was Sie tun können, ist zu nehmen, was es schon gab und bewerten Sie die zusätzlichen Bedingungen selbst.
Last but not least, ich ' ll verlassen Sie mit einem workaround. Wenn die nur, was Sie wollen in der Lage sein zu tun aus dein mapping ist filter den Zeilen, können Sie dies schreiben:
Dies ist eine utility-Methode, mit der das mapping für Sie und akzeptiert Sie einen filter auf die original Person, und nicht das zugeordnete entity. Es könnte nützlich sein, wenn Sie haben viele verschiedene Arten von filtern, aber müssen immer das gleiche tun-mapping.
Persönlich, ich denke, Sie werden besser dran, nur schreiben die Abfragen ordnungsgemäß, indem Sie zuerst bestimmen, was Sie abrufen müssen aus der Datenbank, dann tut jeder Projektionen/mappings, und dann, endlich,, wenn Sie tun müssen weitere Filterung (was Sie nicht sollte), dann materialisieren die Ergebnisse mit
ToList()
oderToArray()
und mehr schreiben Bedingungen gegen die lokale Liste.Versuchen Sie nicht AutoMapper oder einem anderen tool zum ausblenden der realen Entitäten, die von Linq to SQL. Das domänenmodell ist Ihre öffentliche Schnittstelle. Die Fragen, die Sie schreiben, sind ein Aspekt Ihrer private Umsetzung. Es ist wichtig zu verstehen den Unterschied und zu pflegen eine gute Trennung von Bedenken.