Hallo ihr,
Vor einiger Zeit wurde ich in diesem Forum davon überzeugt drei Modelltypen in meiner Webanwendung zu verwenden. Entitymodelle (DBContext weil ich Entityframework verwende), Businessmodelle (z.B. ein Kreuzprodukt der Daten etc.) und die ViewModelle, die nur die Daten repräsentieren, die ich ausgeben möchte.
Soweit stimme ich all dem zu, doch seit ich mich mit oDataControllern beschäftige stoße ich immer wieder auf Beispiele, wo im Controller direkt DBContext aufgerufen wird.
Man könnte nun argumentieren, dass es sich nur um Beispielanwendungen handelt und man es bei real-world Szenarien anders machen würde. Doch folgender Artikel macht mich stutzig:
Data Points - A New Option for Creating OData: Web API
public class AirlinesController : EntitySetController<Airline,int> { private AirlineContext db = new AirlineContext(); public override IQueryable<Airline> Get() { return db.Airlines; }
Und kurz darauf wird folgendes erwähnt:
The Get method needs to return an IQueryable of Airline and that’s what db.Airlines does. This way, the consumer of the OData can define queries over this set, which will then get executed on the database, rather than pulling all of the Airlines into memory and then querying over them.
Und genau hier liegt jetzt meine Frage.
Verliere ich nicht den riesiegen Vorteil, dass oData Queries schon viele Filterfunktionen integriert haben, die dann gegen ein iQueryable ausgeführt werden können?
Wenn ich meine 3 Modelltypen beibehalten möchte (und das möchte ich!), so frage ich mich, wie ich den Nachteil vermeiden kann die tollen Filterfunktionen von oData Controllern + Entity Framework zu verlieren ausgleichen kann.
Obwohl OData all diese Filter zur Verfügung stellt, fange ich jetzt wieder an in meiner Businessebene all dies doch selbst zu machen...
Solange Du überall IQueryable implementierst bleiben alle Filterfunktionen beibehalten.
Du musst in der Business-Ebene einfach die Logik über ExpressionTrees umsetzen und Du kannst alles durch reichen was Du möchtest.
Wir haben das ganz ähnlich für eine ERP-Schnittstelle gemacht: viel Aufwand aber funktioniert wunderbar!
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Okay, das mit dem Durchreichen klingt spitze!
Im Moment lasse ich Automapper von Entity auf Business und von Business auf ViewModelle alles mappen (bzw. kopieren). Ich gehe aber davon aus, dass das mit dem "Durchreichen" dann doch anders geht.
Gibt es ein Tutorial was ich dazu lesen kann? Oder hast du noch einen Tip wie ich lernen kann es so zu machen?
Siehe mein Hinweis bzgl. Entitäten, DB Context und AutoMapper:
Hinweis. AutoMapper niemals mit DbContext mischen. Ist eine ausdrückliche Empfehlung.
Der AutoMapper ist weniger dazu gedacht, dass er Entitäten mappt, viel mehr ViewModels (zu Business Models).
AutoMapper selbst empfiehlt auch ausdrücklich diesen nicht mit einem DbContext zu verwenden.
Expression Trees Beispiele sind auf Stackoverflow und MSDN zig stück 😉
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Okay, verstanden. Ich lese das hier jetzt mal:
How to: Use Expression Trees to Build Dynamic Queries
Hinweis. AutoMapper niemals mit DbContext mischen. Ist eine ausdrückliche Empfehlung.
Der AutoMapper ist weniger dazu gedacht, dass er Entitäten mappt, viel mehr ViewModels (zu Business Models).
D.h. diesen Teil würde ich dann manuell mappen? Oder wie machst du das?
Ich hab nen eigenen Mapper dafür geschrieben (FlexMapper).
Mapping muss manuell erfolgen, verzichtet auf Reflection.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Perfecto! Dann bin ich erstmal versorgt mit Infos. Danke 😃 Frage beantwortet
Jedenfalls Teil 1 meiner Frage. Nachdem ich ein paar Artikel gelesen habe verstehe ich das jetzt so:
var query_where1 = from a in svcContext.AccountSet
where a.Name.Contains("Contoso")
select a;
eine Tree Expression zu generieren. Richtig?
Jede Klasse, die IQueryable implementiert kann diese Expression verstehen und spuckt dann z.B. SQL oder irgendwas anderes aus um auf die Datenquelle zuzugreifen.
Angenommen ich habe jetzt Entityklassen DBSet<Auto>, wo Autos gespeichert sind. Mit dem Flexmapper mappe ich manuell auf Businessmodelle "class Auto" und von denen dann mit dem Automapper auf Viewmodelle "class AutoViewModel".
Wenn ich jetzt alle roten Autos haben möchte, so würde ich das per oData mit einem Filter machen. Der Filter wird jetzt vom API Controller in eine Tree Expression umgewandelt.
Ich darf diese Tree Expression aber nicht direkt auf meine Entityklasse loslassen, sondern muss sie bis dorthin "durchreichen".
Wie dieser Schritt aber technisch funktionieren soll ist mir ehrlich gesagt noch etwas schleierhaft... 😦
Hast du vielleicht noch einen Tip für mich?