# Wozu DAOs/Repositories bei JPA oder Hibernate?



## deamon (15. Feb 2009)

Hallo,

DAOs oder Repositories werden von vielen Entwicklern zusätzlich zu einer Persistenztechnologie wie Hibernate oder JPA verwendet, aber ich frage mich: Wozu?

DAOs kommen eigentlich aus der Zeit vor Hibernate, als man hinter der DAO-Schnittstelle JDBC und SQL versteckt hat. Das DAO war sozusagen die Persistenzschicht. Gewissermaßen als Nachfolger des DAOs wurde das "Repository" erfunden, das eine objektorientiertere Schnittstelle bieten sollte. 

Martin Fowler schreibt dazu in seinem Buch "Patterns für Enterprise Application-Architekturen" (eine schreckliche Übersetzung des Titels!):
"Ein Repository ersetzt spezielle find-Methoden in Data-Mapper-Klassen durch einen spezifikationsbasierten Ansatz der Objektauswahl." 

Was Fowler hier meint, nennt sich bei Hibernate "Criteria". Zumindest für diesen Zweck bräuchte man also keine weitere Klasse, da Hibernate bereits die Merkmale eines Repositorys bietet.

Als weiteren Vorteil gibt er in seinem Buch an, dass man hinter der Repository-Schnittstelle auch andere Datenquellen als relationale Datenbanken verwenden könnte. Aber wenn man bereit ist, sich auf eine relationale DB festzulegen, würde auch dieser Vorteil entfallen.

Blieben noch Tests, bei denen man die DB vielleicht gerne gegen ein Mock-Objekt austauschen würde. Aber sollte man nur dafür wirklich seinen Code mit Repositories aufblähen? Nimmt man dann nicht besser EasyMock oder sowas?

Weiterhin erwähnt Fowler Caching als möglichen Vorteil, aber auch das bietet Hibernate schon ohne zusätzliches Repository.

Vom Austausch der DB beim Test abgesehen, bliebe noch der Vorteil, dass man die Erstellung von Criteria-Objekten in manchen Fällen im Repository machen könnte. Aber auch hier stellt sich mir wieder die Frage: lohnen sie dafür zusätzliche Klassen?

Mir kommt es jedenfalls so vor, als würden DAOs und Repositories von vielen Entwicklern stumpf nach Schema F eingesetzt, obwohl sie oft nicht nötig wären. Was meint ihr dazu? Habe ich bei meinen Überlegungen vielleicht etwas übersehen?

Gruß
Christian


----------



## SlaterB (15. Feb 2009)

ob ein DAO Sinn macht erkennt man genau daran, wie die Situation ist, wenn es nicht da ist,
das kann man sich doch zu 100% selber ausmalen,

ich weiß grad nicht genau worum es geht, sehe da aber zum einen klassenspezifische Lade-Methoden, in HQL oder Criteria jeweils 10 Zeilen lang,
loadPersonBySpecialXYBedingung() {
}
wo sollen solche Methoden definiert sein wenn nicht in einer speziellen Datenbank-Klasse?
je nach Anzahl aufgetrennt in mehrere Klassen, vielleicht spezifisch nur für Person-Methoden, schon ist man bei bei einer Person-DB-Unterstützungsklasse, ob man die nun DAO nennt oder anders

zum anderen finde ich bestimmte Standard-Zugriffe von Hibernate nicht besonders benutzerfreudlich:
Person p = (Person) session.load(Person.class, id);
ist kein vernünftiger Code in einem Java-Programm,
dann doch lieber
Person p = anyHelper.loadPerson( id);
oder, wenn man sowas allgemein aufbauen kann,  gerne
Person p = personDao.load( id);


----------



## maki (15. Feb 2009)

> Mir kommt es jedenfalls so vor, als würden DAOs und Repositories von vielen Entwicklern stumpf nach Schema F eingesetzt, obwohl sie oft nicht nötig wären. Was meint ihr dazu? Habe ich bei meinen Überlegungen vielleicht etwas übersehen?


Was schlägst du denn als Alternative vor?

Den Persistenzcode quer über die ganze Applikation verteilen?


----------



## deamon (15. Feb 2009)

maki hat gesagt.:
			
		

> > Den Persistenzcode quer über die ganze Applikation verteilen?
> 
> 
> 
> Ich glaube das ist genau die Stelle, an der sich viele Entwickler etwas vor machen. Klar, möchte man nicht seinen Code mit SQL verseuchen, aber ob man nun quer durch die Applikation auf die eigenen DAOs/Repositories zugfreift oder auf JPA ist relativ egal. In jedem Fall bindet man den Code an einen wie auch immer gearteten Persistenzmechanismus, auch wenn er hinter einer Fasse versteckt ist. Aber im Falle von JPA wäre das auch eine Schnittstelle, hinter der man Implementierungen tauschen kann.


----------



## ps (15. Feb 2009)

klar, mit JPAQL hat man ja eigentlich eine objektabfragesprache. In kombination mit zB. LiquidForm hat man sogar volles refactoring und keine strings mehr.

aber ich finde es dennoch ziemlich unsauber.. und vor allem unflexibel. zB. könnte die anforderung kommen zugriffe mitzuloggen. oder man möchte nur bestimmten personen erlauben änderungen vorzunehmen. oder oder oder. derartige anforderungen sind wesentlich leichter einzuführen wenn der applikationscode nicht wild in der datenbank herumschreiben kann. Ich habe mir meistens sogar den EntityManager nochmal in einem PersistenceService gekapselt. Hier schreibe ich mir zB. Sachen wie lastChanged, created oder das changeLog mit.

Ein weiteres Beispiel aus der Praxis: Die anwendung wächst, die Userzahl steigt. Suchqueries werden langsam - man möchte lucene einführen. Genial: man weiß sofort an welche stellen man anfassen muss. wenn ich mir vorstelle durch mein application-layer zu gehen und überall den selben code auszutauschen. no mercy.

am ende ist es auch ein DRY prinzip: wenn ich an vielen stellen immer die selben queries habe - dann kapsel ich sie mir lieber in einem Repository (was nur bei DDD sinn macht.. sonst nenn ichs auch einfach nur DAO ;-) )

Das alles sind Beispiele aus meiner Problemdomäne... aber ich kann mir gut vorstellen das es auch in anderen domänen Sinn macht die Zugriffe zu kapseln.


----------



## byte (17. Feb 2009)

deamon - Was hättest Du denn gewonnen, wenn Du keine DAOs / Repositories schreibst? Meinst Du, die Anwendung wird verständlicher oder wartbarer, je weniger Klassen sie enthält? IMO ist genau das Gegenteil der Fall, Stichwort Separation of Concerns.


----------



## deamon (17. Feb 2009)

Vielen Dank für eure Meinungen zum Thema.

Bei meiner Überlegung hatte ich einfach Fälle wie das Speichern von Objekten im Kopf:

```
entityManager.persist(objekt);
```

Da gewinnt man nicht viel, wenn man stattdessen

```
repository.add(objekt);
```
schreibt und dann im Repository in der add-Methode

```
public void add(Object o){
  entityManager.persist(o);
}
```
schreibt. Man hätte einfach nur mehr Code.

Allerdings habt ihr mich nachdenklich gemacht, denn es ist natürlich nicht immer so einfach. Das fängt schon bei dem einfachen Beispiel von SlaterB an:

```
Person p = anyHelper.loadPerson( id);
// statt:
Person p = (Person) session.load(Person.class, id);
```
Und bei längeren Abfragen, bzw. der Erstellung umfangreicher Kriterien für die Abfrage macht sich ein Repository erst Recht positiv bermerkbar.

Das Argument, dass man vielleicht noch Logging oder Autorisierung einbauen möchte, ist zwar berechtigt, aber das könnte man auch sehr elegant mit AOP machen. Wohingegen die hinter der Repository-Schnittstelle mögliche Nutzung von Lucene zum Suchen ein gutes Argument für Repositories ist.

Nach dieser Diskussion denke ich, dass es sich lohnt Repositories zu verwenden, auch wenn der Gewinn bei einfachen Methoden wie persist() nicht besonders groß ist.


----------



## byte (17. Feb 2009)

deamon hat gesagt.:


> Das Argument, dass man vielleicht noch Logging oder Autorisierung einbauen möchte, ist zwar berechtigt, aber das könnte man auch sehr elegant mit AOP machen.



Viel wichtiger als Logging oder Autorisierung ist hier natürlich deklaratives Transaktionshandling. Klar macht man das per AOP, aber auch da ist es doch viel einfacher, wenn man den entsprechenden Code in DAOs oder Repositories gekapselt hat. Denn dann kann man sich einfach Pointcuts für diese Objekte schreiben statt die Aspekte irgendwo im Code zu verwursten.

Und bei der Transaction Propagation kann man auch nicht mehr viel falsch machen. Einfach Propagation.MANDATORY an die DAO-Methoden und Propagation.REQUIRED an alle die DAOs aufrufende Service-Methoden.


----------

