Hallo Leute,
Ich mache einen neuen Thread auf, weil ich über das Thema jetzt schon eine Menge gelesen habe, jedoch alle Lösungsvorschläge im Netz ihre Nachteile zu haben scheinen.
Angenommen ich möchte eine einfache SW schreiben, die Autos verwalten soll.
Auf dem DAL habe ich dann z.B. eine Klasse "CarEntity", im BL eine Klasse "Car" und in der UI eine Klasse "CarViewModel".
Bei der UI kommt jetzt ein oData-Query an:
cars?$filter=name eq 'audi'
In meinem oData Controller kann ich das Query folgendermaßen auffangen:
public IHttpActionResult GetHouses(ODataQueryOptions<DataAccessLayer.Car> qo)
{
}
Im Objekt "qo" ist jetzt mein Query enthalten. Doch schon hier gibt es das erste Problem:
Um dieses Problem zu lösen müsste ich das ankommende Query erst einmal so umwandeln, dass es auf BusinessLayer.Car - Objekte zugreift.
Im BL müsste ich dann eine weitere Umwandlung vornehmen, die auf DAL-Objekte zugreift.
Diese Umwandlung zu schreiben ist aber ein riesiger Aufwand. Ist das also wirklich die richtige Herangehensweise?
Wenn ich nach oData + 3-Layer-Architecture suche finde ich ausschließlich Beispiele, wo es den Entwicklern egal ist und sie direkt auf den DAL zugreifen, wie ich es auch bisher gemacht habe. (z.B. OData FAQ)
Aber mir wurde hier immer wieder genau davon abgeraten...
Ich habe darauf keine Antwort für dich, da ich mir weiterhin die gleiche Frage stelle. Eben auch nicht nach dem ob es generell möglich ist, sondern wie es für kleinere Anwendungen mit vertretbarem Aufwand möglich ist.
Ich habe im Rahmen von [Review] Best Practices/Architektur anhand von Bespielprojekt (WebApi + OData + EF + SPA (Aurelia)) auch mit AutoMapper etc. experimentiert und finde, dass dieser viele Punkte ganz gut lösen kann.
(auch wenn Abt immer wieder erwähnt, dass man diesen nicht nutzen soll und auch entsprechende Links dazu liefert. Ich fand allerdings nicht, dass diese noch vollständig zutreffen, da AutoMapper mittlerweile auch eine Projektions-Extension mitbringt.)
Um allerdings die harte Bindung an deinen DAL zu verlieren, kannst du die Entities auf jeden Fall in eine eigene DLL auslagern.
Ausser bei einer SW die OData selber als Aufgabe hat, sehe ich keinen einzigen Grund warum die UI in OData mit darunter liegenden Schichten reden sollte.
Die UI hat beim BL gefälligst ein DataService.GetCarById(id) abzufragen.
Aber dann gehen mir doch alle Möglichkeiten, die oData liefert verloren. Da kann ich auch gleich das Protokoll vergessen und wieder mit normalem REST arbeiten.
Welchen Sinn haben oData-Queries in der URL, wenn ich dann im BL doch alles neu schreiben muss?
OData ist keine Eierlegende Wollmilchsau.
Es hat Vor- wie Nachteile.
OData selbst gibt Dir nur einen Rahmen, wie Du Nachrichten austauschst - mit gewissen Standardfeldern.
Es gibt hier auch andere Basen, wie zB. Siren, oder Json-LD oder HAL..... alle haben einen Fokus und eben die Vor- und Nachteile.
Wie ichs im anderen Thread schon gesagt habe:
OData sollte nicht direkt mit den Entitäten arbeiten. OData arbeitet gegendie Business-Schicht und diese stellt Expression Trees zur Verfügung.
Genau so kannst Du die Vorteile von OData wie Filter und Selects auch weitergeben und trotzdem das 3-Schichten-Modell verfolgen.
Du musst sie nicht neu schreiben. Auch das hab ich Dir bereits gesagt (und zwar hier: oData Queries auf Datenbank oder lokale Objekte).
Die Beispiele machen das nicht, weil das oft erschlägt. Das ist auch nicht das Ziel solcher Beispiele.
Entitäten haben i.d.R. Felder, die Du gar nicht nach Außen mitgeben willst oder darfst oder kannst.
Das ist übrigens auch mein Feedback in [Review] Best Practices/Architektur anhand von Bespielprojekt (WebApi + OData + EF + SPA (Aurelia))
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
OData sollte nicht direkt mit den Entitäten arbeiten. OData arbeitet gegendie Business-Schicht und diese stellt Expression Trees zur Verfügung.
Genau so kannst Du die Vorteile von OData wie Filter und Selects auch weitergeben und trotzdem das 3-Schichten-Modell verfolgen.
Genau das ist der Punkt, an dem ich jetzt schon so lange recherchiere. Ich weiß, was ein Expression Tree ist, doch ich habe keine Ahnung, wie ich dieses Wissen jetzt verwenden soll.
Ich habe die anderen Beiträge schon gelesen und versucht herauszufinden, was du meinst.
Sorry, grad nur am Handy und daher anständiges Tippen suboptimal; aber such mal nach ODataUriParser.
Oder: Du machst das EntitySet von Odata nicht auf Entitäten, sondern auf BusinessModelle.
Die Schicht zwischen Business Modell und OData implementiert dann eben diesen Expression Tree oder einen Mapper, der IQueryable<Model, Entity> unterstützt.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ok - der Begriff ist vermutlich auch für t0ms3n interessant:
Hallo zusammen,
- Im OData Bereich ist es mir weiterhin rätselhaft, wie es möglich ist, dort nicht die Entitäten der Datenbank zu nutzen und trotzdem die OData Funktionalitäten zu erhalten
.
Denn das hieße ja, dass ich mit dem UriParser erst einmal alle Informationen aus der URI bekomme.
Im BL baue ich dann anhand dieser Informationen einen Expression Tree, der am Ende auf das IQueryable des EF losgelassen wird. Bin ich da auf dem richtigen Weg?
Klingt dennoch nach viel Aufwand...
Klingt dennoch nach viel Aufwand...
Keine Frage; das ist es. Habe auch nie was anderes behauptet 😃
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ihr stürzt mich in das Land der Tränen 😄
Dann ist es für kleine Anwendungen overkill es so zu machen, richtig?
Warum?
Dann ist es für kleine Anwendungen overkill es so zu machen, richtig?
Das kann man pauschal nicht sagen. Das muss man abschätzen und evaluieren.
Wenn die API klein ist aber tausende von Clients (die man oft nicht kennt) zugreifen, wird sich OData aufgrund der Vorteile i.d.R. lohnen.
Aber es gibt auch andere Hypermedia-Ansätzen wir Siren oder Json-LD, die evtl auf das ein oder andere besser passen als OData.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Denn das hieße ja, dass ich mit dem
> erst einmal alle Informationen aus der URI bekomme.Im BL baue ich dann anhand dieser Informationen einen Expression Tree, der am Ende auf das IQueryable des EF losgelassen wird. Bin ich da auf dem richtigen Weg?
Also stimmte diese Vermutung. So geht es?
Ja. Im Prinzip ist das aber auch genau, was man "von Hand" machen würde, nur abstrahiert.
LaTino
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
Es geht ohne Expression Trees!
Ich habe noch etwas recherchiert und jetzt folgendes herausgefunden:
z.B. geht das so:
//getEdmModel() liefert das EdmModel der entsprechenden Schicht
ODataQueryOptions dqo = new ODataQueryOptions(new ODataQueryContext(GetEdmModel(), typeof(DataAccessLayer.House), qo.Context.Path), qo.Request);
Somit kann ich mir den aufwändigen Weg über Expression Trees sparen und verletze nirgendwo die 3 Schichten. Ich hoffe niemand hat jetzt wieder ein super Gegenargument und sagt mir, dass dieser Weg der total falsche ist 😄
Du hast ein EdmModel für die unterschiedlichen Schichten? Das klingt für mich nun allerdings zu mindestens merkwürdig 😃.
Naja - nicht wirklich. Auf der obersten Ebene nur noch um den URL String zu bekommen. Versuche gerade das zu löschen. Im BL keins mehr und nur noch ganz unten im DAL.
Ich versteh auch nicht ganz, wie das funktionieren soll.
Aber vielleicht, sofern das am Ende klappt, könntest Du das mal an einem Beispiel illustrieren.
Immer interessant, wenn es irgendwie effizienter geht.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Wenn ich eine fertige Lösung habe, die super funktioniert, poste ich es hier auf jeden Fall rein.
@david777 Na wie siehts aus ? 😉
Ein umgesetztes Beispiel dazu würde mich auch interessieren.