Laden...

oData Queries auf Datenbank oder lokale Objekte

Erstellt von david777 vor 7 Jahren Letzter Beitrag vor 7 Jahren 1.874 Views
D
david777 Themenstarter:in
37 Beiträge seit 2016
vor 7 Jahren
oData Queries auf Datenbank oder lokale Objekte

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...

16.842 Beiträge seit 2008
vor 7 Jahren

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!

D
david777 Themenstarter:in
37 Beiträge seit 2016
vor 7 Jahren

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?

16.842 Beiträge seit 2008
vor 7 Jahren

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 😉

D
david777 Themenstarter:in
37 Beiträge seit 2016
vor 7 Jahren

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?

16.842 Beiträge seit 2008
vor 7 Jahren

Ich hab nen eigenen Mapper dafür geschrieben (FlexMapper).
Mapping muss manuell erfolgen, verzichtet auf Reflection.

D
david777 Themenstarter:in
37 Beiträge seit 2016
vor 7 Jahren

Perfecto! Dann bin ich erstmal versorgt mit Infos. Danke 😃 Frage beantwortet

D
david777 Themenstarter:in
37 Beiträge seit 2016
vor 7 Jahren

Jedenfalls Teil 1 meiner Frage. Nachdem ich ein paar Artikel gelesen habe verstehe ich das jetzt so:

  1. Mein oData Controller wandelt automatisch die URL in eine LINQ Tree Expression um.
    Auch folgendes LINQ-Beispiel tut intern nichts anderes als aus:
var query_where1 = from a in svcContext.AccountSet
                    where a.Name.Contains("Contoso")
                    select a;

eine Tree Expression zu generieren. Richtig?

  1. Jede Klasse, die IQueryable implementiert kann diese Expression verstehen und spuckt dann z.B. SQL oder irgendwas anderes aus um auf die Datenquelle zuzugreifen.

  2. 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?