Laden...

Repositories und Dependency Injection

Erstellt von Ahrimaan vor 12 Jahren Letzter Beitrag vor 12 Jahren 1.681 Views
A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren
Repositories und Dependency Injection

verwendetes Datenbanksystem: <NHibernate>

Hallo zusammen,

ich "streite" mich gerade ein wenig mit meinem Kollegen:

Er, ehemaliger Delphi Progger, kennt sowas wie Repository und DI nur Theoretisch 😉 .

So nun zum Streitthema : Ich habe ein Interface IRepository<T> also generisch.
Dieses Interface nutze ich als Contract für meine anderen Repositories.
Um die Repositories in meine Anwendung zu Injecten lagere ich die Entität des Repositories (also das <T> zB UserModel) in andere Assemblys aus um diese später nutzen zu können.
Er sagt, er würde die Entität aber in das jeweilige Repository mit einbinden.

zB die Assembly UserRepository enthält die Entität User

Nur : Habe ich dann ja wieder den harten Verweis auf das Repository und das will ich ja verhindern.
Ich gebe ihm aber recht, dass ein Verweis auf dieEntität auch nicht soo toll ist, aber zur Zeit fällt mir keine andere Lösung ein.

Wer ist also näher an der Wahrheit ?

Grüße

S
417 Beiträge seit 2008
vor 12 Jahren

Hallo,

ich sehe irgendwie den Zusammenhang zum DI nicht. Es geht dir doch rein
um die Aufteilung der Klassen in Assemblies oder hab ich das falsch verstanden?
Für ein DI ist es ja egal in welcher Assembly die jeweilige Komponente liegt.

A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren

naja es geht hier darum :

Klasse A braucht IRepository<Person>

Das IRepository soll nun per DI Injected werden.

Variante A : Ich habe die Entität im PersonRepository
Dann MUSS Klasse A ein Verweis auf PersonRepository haben, damit es klappt
DI wäre dann auch realtiv witzlos

Variante B: Ich habe die Entität in einer eigenen Assembly
Dann MUSS Klasse A nur den Verweis auf die Entität haben, nicht auf das Repository selbst
DI macht wieder Sinn

Grüße

S
417 Beiträge seit 2008
vor 12 Jahren

Mit Verweis auf PersonRepository meinst du den Verweis auf die Assembly in der PersonRepository definiert ist oder?
Wichtig ist letztendlich nur, dass du in der Klasse A die Abhängigkeit zu einer Schnittstelle (in dem Fall IRepository<Person>) und nicht zu einer konkreten Implementierung hast.
In welcher Assembly die spätere konkrete Implementierung dafür dann liegt, ist aus meiner Sicht nicht so wichtig.

A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren

Hi Sarc, ja in einer Assembly

Also sehe ich das Richtig, dass ich dann ein generische IRepository Injecte und nur die Entität als fester Verweis angegeben wird.

Gut Danke 😃

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Ahrimaan,

Person ist Bestandteil des (Daten-) Model und hat im DAL nicht direkt was zu suchen. Der DAL - sprich hier das Repository - kann es kennen, aber deklariert sollte es im Model-Namespace (und ev. Model-Assembly) sein.

Ein Verweis bezieht sich immer auf eine konkrete Instanz, hier geht aber um den Typparameter des generischen Repositories.

Insofern ist mir nicht klar was ihr (du und ein Kollege) mit Verweis und Einbinden meint.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren

Hi Gü,

Person ist Bestandteil des (Daten-) Model und hat im DAL nicht direkt was zu suchen. Der DAL - sprich hier das Repository - kann es kennen, aber deklariert sollte es im Model-Namespace (und ev. Model-Assembly) sein.

Genau darum ging es. Mein kollege ist der Meinung das Datenmodel MUSS in den DAL rein , ich sage es ist nicht so.

Damit hast du meine Aussage bekräftigt. Danke 😃

Grüße

5.941 Beiträge seit 2005
vor 12 Jahren

Hallo zusammen

@gfoidl
Ich nehme an, dass Ahrimaan mit "Verweis" eine harte Assemblyreferenz meint, die ja bei irgendeiner Typabhängigkeit - ob als Typargument oder wegen der Nutzung für eine Instanz - immer vorhanden ist.

@Ahrimaan
Rein theoretisch kannst du alles in einer Assembly haben, komplett alles.
Auch dann hat DI noch alle Vorteile (bis auf die Austauschbarkeit der Implementation ohne Neukompilierung).

Der Vorteil ist, dass du die Abhängigkeit vom konkreten Typen gelöst hast und die konkreten Typen zentral konfigurieren kannst, durch ein Austausch an einer Stelle.

Aber das halte ich nicht für sinnvoll, wie gfoidl sagt, sollte die Assembly-Aufteilung logisch sein und Solution-interne Abhängigkeiten minimieren. Wie feinkörnig ist dann wieder eine andere Entscheidung.

Der einzige zusätzliche Vorteil, wenn du bspw. die Interfaces und Implementierungen für die Repositories nicht in einer Assembly hast - und das ist die Voraussetzung dafür, also:

  • Project.Data.Interfaces

  • Project.Data.Sql

  • Project.Data.Xml

ist die Austauschbarkeit der Implementation, ohne das du irgendetwas neu kompilieren musst, nur per Registrationsänderung in einer Xml-Datei.

Nur wenn du das brauchst, macht es Sinn, keine harten Referenzen zu haben und die Assemblies feinkörnig aufzuteilen.

Meistens braucht es dies nicht und die Nachteile, die diese Vorgehensweise mit sich zieht, sind grösser als die Vorteile.

Mein kollege ist der Meinung das Datenmodel MUSS in den DAL rein , ich sage es ist nicht so.

Wenn du nicht feinkörnige Assembly-Unterteilungen machst, kannst du die Entities / Models in deine DAL-Assembly packen. Wenn feinkörniger, gehören diese zumindest logisch zusammen. Das ergibt sich auch aus der mindestens weichen, wenn nicht harten Referenz.

Was versteht er unter "DAL"?
Eine Assembly? Eine logische Zusammenhörigkeit?

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren

Hi Peter,

mein Kollege meint mit DAL schon eine Assembly, welche den Datzenzugriff regelt.

Rein theoretisch kannst du alles in einer Assembly haben, komplett alles.
Auch dann hat DI noch alle Vorteile (bis auf die Austauschbarkeit der Implementation ohne Neukompilierung).

Das verstehe ich aber nicht so recht : Wenn ich eh eine Konkrete Implementierung in eine Assembly packe, muss ich ja nicht mehr zwingend gegen das interface schreiben, sondern kann direkt auf die Implementation zugreifen, da ich die Assembly ja eh eingebunden habe.

Nur wenn du das brauchst, macht es Sinn, keine harten Referenzen zu haben und die Assemblies feinkörnig aufzuteilen.

Meistens braucht es dies nicht und die Nachteile, die diese Vorgehensweise mit sich zieht, sind grösser als die Vorteile.

Wieso gibt es da so viele Nachteile ? So wie ich das sehe , verdrahte ich in meiner jeweiligen Klasse ja nur 2 Assemblys : Das Model als Assembly und das Interface des generischen Repositorys, wessen konkrete Implementierung ich über den DI Container auflöse.
Das wäre eigtl. gängiger Standard um absolut Austauschbar zu bleiben oder irre ich mich da ?

Grüße

5.941 Beiträge seit 2005
vor 12 Jahren

Hallo Ahrimaan

Das verstehe ich aber nicht so recht : Wenn ich eh eine Konkrete Implementierung in eine Assembly packe, muss ich ja nicht mehr zwingend gegen das interface schreiben, sondern kann direkt auf die Implementation zugreifen, da ich die Assembly ja eh eingebunden habe.

Das ist genau der Punkt.

Gegen ein Interface implementieren "reicht", könnte man sagen.

Ob du auf die Implementation eine harte Referenz hast / oder diese im gleichen Assembly hast (ist hierfür beides dasselbe), resultiert einzig und alleine nur im Unterschied, dass du die ganze Anwendung neu kompilieren musst, um deine Anwendung auf einer andere Implementation umzubiegen. Das ist aber alles.

So wie du schreibst, beziehst du den zweiten Teil - der nicht so relevant ist - als der Grund für DI, bzw. dass es ohne diesen keine Rolle spielt.

Genau das ist eben nicht so.

Ausser du meinst mit "nicht mehr zwingend" die Gefahr, das du aus Versehen irgendwo den konkreten Typen benutzt, weil du ihn benutzen kannst.

Wieso gibt es da so viele Nachteile ? So wie ich das sehe , verdrahte ich in meiner jeweiligen Klasse ja nur 2 Assemblys : Das Model als Assembly und das Interface des generischen Repositorys.
Das wäre eigtl. gängiger Standard um absolut Austauschbar zu bleiben oder irre ich mich da ?

Ich muss mich korrigieren: "Man handelt sich damit einige Nachteile ein, die nicht sein müssten, wenn man den einen Vorteil nicht braucht".

Als Beispiel kannst du in deiner Anwendung die DI-Registrierung nicht per Code machen (Delegates), auch die NHibernation müsstest du per Xml machen.

Das ist ein wesentlicher Nachteil, da die Typsicherheit und der Komfort der Registrierung nachlässt.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

A
Ahrimaan Themenstarter:in
350 Beiträge seit 2010
vor 12 Jahren

Hallo Peter,

Ausser du meinst mit "nicht mehr zwingend" die Gefahr, das du aus Versehen irgendwo den konkreten Typen benutzt, weil du ihn benutzen kannst.

Genau das meine ich 😃

Als Beispiel kannst du in deiner Anwendung die DI-Registrierung nicht per Code machen (Delegates), auch die NHibernation müsstest du per Xml machen.

Das ist ein wesentlicher Nachteil, da die Typsicherheit und der Komfort der Registrierung nachlässt.

Stimmt das wäre in dem Sinne unkomfortabel. Ich habe aber bewusst diese Art der implementierung gewählt, da ich mit FluentNhibernate ohne "Harte" Koppelung bei Änderungen nur die dll des Repositorys nachschiebe.

Grüße

T
6 Beiträge seit 2011
vor 12 Jahren

Keine Ahnung ob das gut ist, aber ich mach das so:

-Project.Module1
-Project.Module2
-Project...
-Project.Shared
-Project.Dal

In Shared sind die Interfaces, Entities usw. auf die alle den Zugriff brauchen und die von allen referenziert wird. Der Rest läuft über DI.

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo temilun,

die Entities würde ich nicht in Shared haben (wollen). In Shared können, wie du es auch hast, die Interfaces liegen und sonstige geteilte Funktionalitäten wie Erweiterungsmethoden, Logging-Komponente, etc.

Die Entities, wenn sie POCOs sind, gehören in einen eigenen Model-Namespace (und ev. auch in ein eigenes Projekt).

Somit ergibt sich grob solche Struktur (der Solution):


MySuperApplication
- MySuperApplication.Shared (od. z.B. auch als Common bezeichnet)
- MySuperApplication.DataAccess
- MySuperApplication.Services
- MySuperApplication.Models
- MySuperApplication.ViewModels
- MySuperApplication.View
- MySuperApplication (die EXE, die nicht viel mehr macht als alles (per DI) zu laden und verbinden)

auf die Test-Projekte hab ich hier verzichtet, die gehören aber auch dazu. Angehängt ein Bild das die Schichten zeigt, die ähnlich obiger Projektstruktur sind ,nur die Bezeichnungen sind tw. anders. Das Bild hab zwar ich generiert, aber der Code stammt von einem MS ALM-Ranger-Demo-Projekt. Die Pfeile zeigen die Abhängigkeiten zwischen den einzelnen Projekten.

Aber: die Strukturierung eines Projekts ist z.T. auch Geschmackssache und bietet somit viel Raum für Diskussionen. Von daher bitte das in diesem Thread nicht zu intensiv behandeln.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"