Laden...

oData und die 3-Schichten-Architektur

Erstellt von david777 vor 7 Jahren Letzter Beitrag vor 7 Jahren 4.431 Views
D
david777 Themenstarter:in
37 Beiträge seit 2016
vor 7 Jahren
oData und die 3-Schichten-Architektur

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:

  1. Weil das Query am Ende auf DataAccessLayer.Car -Objekte losgelassen werden soll habe ich keine andere Wahl als den Typ hier mit anzugeben. Mein UI-Layer soll aber die Datentypen aus dem DAL nicht kennen dürfen.

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

T
314 Beiträge seit 2013
vor 7 Jahren

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.

F
10.010 Beiträge seit 2004
vor 7 Jahren

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.

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

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?

16.807 Beiträge seit 2008
vor 7 Jahren

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

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

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.

  1. Wie bekomme ich meinen oData-Request auf einen Expression Tree "gemappt"?
  2. Wie komme ich überhaupt an den Expression Tree meiner oData Abfrage?

Ich habe die anderen Beiträge schon gelesen und versucht herauszufinden, was du meinst.

16.807 Beiträge seit 2008
vor 7 Jahren

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.

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

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

16.807 Beiträge seit 2008
vor 7 Jahren

Klingt dennoch nach viel Aufwand...

Keine Frage; das ist es. Habe auch nie was anderes behauptet 😃

T
314 Beiträge seit 2013
vor 7 Jahren

Ihr stürzt mich in das Land der Tränen 😄

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

Dann ist es für kleine Anwendungen overkill es so zu machen, richtig?

16.807 Beiträge seit 2008
vor 7 Jahren

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.

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

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?

3.003 Beiträge seit 2006
vor 7 Jahren

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)

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

Es geht ohne Expression Trees!
Ich habe noch etwas recherchiert und jetzt folgendes herausgefunden:

  1. Im Controller Queryable deaktivieren
  2. Dort ODataQueryOptions vom Typ "ViewModel" der Presentationsschicht holen
  3. Die Queryoptions können an den BL gegeben werden und dort in ODataQueryOptions vom Typ des BL (bzw. DAL) umgewandelt werden:

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 😄

T
314 Beiträge seit 2013
vor 7 Jahren

Du hast ein EdmModel für die unterschiedlichen Schichten? Das klingt für mich nun allerdings zu mindestens merkwürdig 😃.

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

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.

16.807 Beiträge seit 2008
vor 7 Jahren

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.

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

Wenn ich eine fertige Lösung habe, die super funktioniert, poste ich es hier auf jeden Fall rein.

M
177 Beiträge seit 2009
vor 7 Jahren

@david777 Na wie siehts aus ? 😉

Ein umgesetztes Beispiel dazu würde mich auch interessieren.