Laden...

Welche Logik kommt wohin in der 3-Schichtenarchitektur und dem Entity Framework?

Erstellt von BlackMatrix vor 9 Jahren Letzter Beitrag vor 8 Jahren 2.502 Views
B
BlackMatrix Themenstarter:in
218 Beiträge seit 2012
vor 9 Jahren
Welche Logik kommt wohin in der 3-Schichtenarchitektur und dem Entity Framework?

Ich habe ein paar unspezifische Fragen zum Schichtenmodell und dem Entity Framework.

Ich nutze EF 6.1.3 und das generische Repository Framework Framework. Das Framework bietet generische Basisklassen und Interfaces für Repository, Services und dem Unit of Work Pattern.

Das Grundprinzip hinter EF ist ja zunächst einmal die Daten einer Anwendung zu speichern. Ich habe in meiner .NET Anwendung CLR-Objekte, die ich mittels Entitäten abbilden will und dabei sollte es Aufgabe sein nur so viele Informationen abzuspeichern, dass man im Anschluss die CLR-Objekte nach Neustart wiederherstellen kann.

  1. Ich habe nun bei fast jedem CLR-Objekt gemerkt, dass ich in meiner Serviceschicht eigentlich immer Konvertierungen Entity <--> CLR-Objekt anbieten muss. Sieht man bei den Beispielen im Netz eigentlich nie, da wird direkt mit Entitäten gearbeitet und ich frage mich, ob ich hier evtl. was falsch mache.

  2. Wenn man die Entität IPEndPointEntity als Beispiel zu Rate zieht und möchte, dass in der Datenbank jeweils jede IP-Adresse + Port nur einmal vorhanden ist. Ist dies dann Aufgabe vom Entity Framework, dass der Constraint von IPAddress und Port Unique ist oder muss das in der Repositoryschicht abgefangen werden? Oder vielleicht sogar von beiden? Wie erreicht man dies im EF mittels FluentAPI?

  3. Wenn ich bereits Objekte in meiner Datenschicht habe und ich von außen neue hinzufügen bzw. updaten möchte, bei denen ich noch nicht weiß, ob exakt diese Objekte schon in der Datenbank vorhanden sind. Ist es dann Aufgabe der BL, dass zunächst das mögliche, bereits vorhandene Objekt geholt wird, um dieses dann upzudaten?

  4. Wenn ich ein CLR-Objekt habe, welches mehrere CLR-Objekte als Properties haben, die jeweils auch letztendlich auch als Entitäten in der DAL hinterlegt werden sollen, welche Schicht ich dann dafür zuständig, sodass diese dann korrekt in der Datenbank landen?

So, ich glaube das war es erstmal 😃

16.834 Beiträge seit 2008
vor 9 Jahren
  1. Web-Beispiele sind zu 99% abstrakt und haben mit einer übersichtlichen und realen Architektur oft wenig am Hut.
    Ich nenne meine DB Entitäten zB "PersonEntity" und das Objekt, mit dem die Software dann in der Business-Logik arbeitet, dann zB "Person".
    Mappen ist hier normal und gehört zum Beruf.
    Das EF ist halt einfach der DAL.

  2. Das ist Definitionssache.
    Zum einen kannst Du Deine Entität vorher prüfen in der Repository-Schicht, Du kannst dies in der Service-Schicht (Business Layer) prüfen und als Constraint in der DB prüfen.
    Ich kenne genug Systeme, die solche Überprüfungen im Code machen und nicht in der DB; wobei natürlich die DB hier "besser" ist - aber auch nicht immer.
    Pauschale Aussage: gibts nicht. Ratsam: in der DB.

  3. Keine pauschale Aussage möglich.
    Kommt auf die Gesamtanwendung an

  4. BL

742 Beiträge seit 2005
vor 9 Jahren
  1. Der Begriff Repository ist ein bisschen überstrapaziert, weil jeder diesen anderst verwendet. Ich mach das leider auch, sogar unterschiedlich in der gleichen Anwendung. Im Folgenden meine ich mit Daten-Objekte übrigens Klassen, die nur dazu erzeugt werden um sie in eine Datenbank (SQL, XML) zu serialisieren. Entitäten ist hier nämlich ein recht unpräziser Begriff.

Ich würde hier zwei Fälle unterscheiden, die ich bisher gesehen habe:

a) Das Repository wird verwendet um Domänen-Objekte zu Speichern (http://martinfowler.com/eaaCatalog/repository.html). Dabei gibt es Fälle, bei denen du dein Domänen-Objekt nicht mehr mappen musst, zum Beispiel weil der intern verwendete O/R Mapper schon komplexe Mappings kann und man die Konvention überschreiben kann. Das ist in Ordnung (und pragmatisch), man sollte dabei aber zugunsten des O/R-Mappers keine Abstriche beim Design des Domänen-Objekts machen. Wenn du keinen Public Setter willst, aber der O/R-Mapper braucht einen, solltest du diesen nicht extra einführen. Stattdessen ist es dann oft notwendig, eigene Daten-Objekte zu erstellen und das Mapping innerhalb des Repositories durchzuführen. Meiner Meinung nach ist dass die schönere Verwendung, weil du hier wirklich von der Datenhaltung abstrahieren kannst, inklusive Mapping usw.

b) Über das Repository werden Daten-Objekte gespeichert und geladen. Das Mapping übernimmt dann oft irgendein Service Layer / Manager. Problematisch kann dabei sein, dass man die Data-Entitäten so designt, dass es für den O/R Mapper bequem ist und man implizite Abhängigkeiten hat. Viele verwenden auch keine eigenen Domain-Objekte, sondern arbeiten im Domain Layer nur mit diesen Daten-Objekte. Das ist aber eigentlich ein Anti-Pattern, weil dann die Business-Logik in allen möglichen Managern verlagert wird (http://www.martinfowler.com/bliki/AnemicDomainModel.html).

=> Es kommt halt drauf an 😉

  1. Ich würde hier die Regel befolgen, dass du soviel wie möglich in der Business-Logik validierst und nur wenn nötig über die Datenbank. Bei Eigenschaften, die nicht mehrmals vorkommen können ist die Validierung über die Datenbank aber der einfachste und pragmatischste Ansatz. Insbesondere auch, weil due Nebenläufigkeitsprobleme vermeiden kannst.

  2. Sie Abt. Ich mach das aber so.

  3. Hier würde ich mal über Aggregates nachdenken: http://martinfowler.com/bliki/DDD_Aggregate.html, das sind Objekte die eine Einheit bilden, beispielsweise Product und Product-Images. Ein guter Ansatz kann es sein, pro Aggregate ein Repository zu erstellen und gemeinsam abzuspeichern. Ausnahemen bestätigen aber natürlich die Regel.

B
BlackMatrix Themenstarter:in
218 Beiträge seit 2012
vor 8 Jahren

Erst einmal vielen Dank für eure Antworten.

  1. [...] Ich nenne meine DB Entitäten zB "PersonEntity" und das Objekt, mit dem die Software dann in der Business-Logik arbeitet, dann zB "Person".

Das ist gut, das habe ich nämlich auch so gemacht. Mich stört allein schon eine ID irgendwelcher Objekte in meiner BL. Evtl. für die Suche mittels Kundennummer, aber grundsätzlich ist es mir in der BL z.B. egal welche ID die Adresse meiner Person hat. Allein aus diesem Grund gibt es bei mir Address und AddressEntity.

  1. Sehe ich das richtig, das ein Unique-Constraint über eine oder mehrere Spalten erst mit dem EF 6.1 eingeführt worden ist? Ich habe es nämlich so gelöst:
class IPEndPointEntityMap : EntityTypeConfiguration<IPEndPointEntity>
	{
		public IPEndPointEntityMap()
		{
			HasKey(x => x.Id);

			Property(x => x.Address)
				.IsRequired()
				.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("IX_IPEndPoint", 1) {IsUnique = true}));

			Property(x => x.Port)
				.IsRequired()
				.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("IX_IPEndPoint", 2) { IsUnique = true }));
		}

Das sorgt erstmal dafür, dass in die DB keine gleichen Objekte eingefügt werden können. Grundsätzlich empfiehlt es sich dann dennoch in der BL abzufragen, ob der IPEndPoint schon vorhanden ist, damit keine Exceptions fliegen.

Noch eine Frage zur Implementierung von Entitäten. Aus welcher Sicht heraus entwickle ich diese? Meine PersonEntity hat z.B. einen Vornamen. Nun könnte ich dieser einer string als Property spendieren, so wie es mein reales Personobjekt auch aufweist, oder aber ich lege eine FirstNameEntity an um auf Normalisierung in der DB zu achten und jeden Vornamen nur einmal in der Datenbank zu haben und diesen mittels ID zu referenzieren. Auf der anderen Seite habe ich aber gehört, dass man mit dem EF sich keine Gedanken mehr um die Datenbank machen braucht. Evtl. gibt es für solche Fälle auch wieder Eintstellmöglichkeiten im EF um keine extra Entität einzuführen. Wenn ja welche, aber letztendlich müsste ich, wenn ich eine FirstNamEntity einführe auch wieder ein Uniquekonstrukt (wie oben) für den Vornamen einführen (der wirklich erst mit EF 6.1 hinzugekommen sein soll)?

Viele Grüße

BlackMatrix

P
1.090 Beiträge seit 2011
vor 8 Jahren

Grundlegend musst du dir einfach überlegen, ob die Aspekte zu deiner Geschäftslogik gehören oder zum DAL.

Mal als einfaches Beispiel. Wenn du im DAL bei einer SQL Datenbank ein ID hast muss diese im DAL eindeutig Sein. Für deinen BL ist sie nicht so wichtig. Eine vorgabe für den BL könnte z.B. bei Benutzern sein, dass es eine E-Mail Adresse nur einmal gibt.

Überleg einfach ob du deinem DAL einfach austauschen kannst und statt einer DB z.B. einer Textdeitei verwenden kannst. Wenn das funktioniert bist du schon mal auf den richtigen Weg.

Das man sich mit einen O/R Mapper keine Gedanken um die DB machen muss, ist nicht wirklich richtig.
O/R Mapper sollen dir einfach viel Arbeit abnehmen. Was für viele standard Sachen auch reicht.
Wenn du eine wirklich performante DB zugriff brauchst, solltest du keinen O/R Mapper verwenden und wirklich versthen wie die DB Arbeitet.

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern