# DAO Pattern - Relationen mit DTO abbilden



## timomeinen (16. Jun 2005)

Das DAO-Pattern bietet eine Abstraktion auf die Persistenzschicht.

Gegeben sei eine n:m Relation zwischen den Datenbanktabellen Kunde und Artikel über eine Übergangstabelle Bestellung:

Kunde n----1 Bestellung 1----m Artikel

Kunde-Artikel sei hier als Beispiel genannt. Das Problem tritt bei jeder Relation im DAO-Pattern auf!

Die Daten werden über DataTransferObjects (DTO) ausgetauscht. Es gibt also KundeDTO und ArtikelDTO. In der KundeDTO gibt es eine Collection der Bestellungen, welche alle ArtikelDTO beinhalten, die der Kunde bestellt hat.

Bsp. Collection<ArtikelDTO> getAllArtikel();

In der ArtikelDTO wiederum gibt es eine Collection aller KundeDTOs, die mit diesen Artikeln verknüpft sind. Da es dann auch in ArtikelDTO eine Methode gibt, wie Collection<KundeDTO> getAllKunden(); entsteht leicht ein "Kreislauf":

Ich komme an eine KundeDTO und hole mir eine ArtikelDTO und daraus wieder eine KundeDTO usw.


Meine Frage ist nun die Erstellung der DTOs. Falls man streng Objektorientiert vorgehen würde, müsste man beim erstellen einer DTO auch alle abhängigen DTOs bilden und der Klasse hinzufügen. Es würde jedoch sofort zu einer Endlosschleife kommen.


Wir haben uns bisher 2 mögliche Auswege gesucht:

1. Es werden in der DTO nicht die abhängigen DTOs gespeichert, sondern nur die IDs
Vorteil: Keine Rekursion
Nachteil: Keine "echte" objektorientierung, da ich, um an eine abhängige DTO zu gelangen, mit der ID eine DAO-Methode aufrufen muss.

2. Unterschiedliche DAO-Methoden zum generieren der DTO:
  I. Die DTO enthält keine weiteren DTOs, sondern nur die abhängigen IDs. Um an eine abhängige DTO zu gelangen, muss mit der gespeicherten ID eine DAO-Methode aufgerufen werden.

  II. Man erhält eine DTO mit genau EINER Stufe abhängiger DTOs. Z.B. wäre in Kunde eine Collection aus ArtikelDTOs, welche jedoch vom Typ I. wären. In ihnen steckt also anstatt einer DTO eine ID.

Vorteil: In den meisten Fällen dürfte eine STufe ausreichend sein. Zur Not gelangt man über die ID an eine DTO.
Nachteil: 2 unterschiedliche Arten von DTOs. Erhöhter programmieraufwand.


Die mir bekannte Literatur überlässt es dem Progrmmierer dieses Problem zu meistern. _Core J2EE Patterns_ geht überhaupt nicht auf das Problem ein.

Kennt jemand Best-Practices zu diesem Problem oder hat eine bessere Möglichkeit die Abhängigkeiten aufzulösen?

Danke und

Glück Auf
Timo


----------



## Bleiglanz (16. Jun 2005)

hab ich auch mal gemacht


```
getValueObject(int depth)
```

ist eher übel, weil der "rekursive" Auflöser extrem aufwändig geworden ist, das Problem ist einfach unlösbar:

bei voller übernahme würde das DTO eine riesieges Objektnetz werden, und zur Vermeidung von Duplikaten müsste man noch eine ID-Map verwenden (damit keine Records doppelt reinwandern)

sowas wär irgendwie bizarr

mach jetzt meistens die Lösung mit den Fremdschlüssel IDs, dann gehts wenigstens in einem Rutsch (und wenn man die abhängigen nicht braucht hat man keine Zeit verschwendet)

ggf. eine (Session-Bean) Methode schreiben getAllArtikel(List<Integer>), in die man die im DTO enthaltene Liste gleich reinstecken kann

wirklich gut ist das natürlich auch nicht, den vollen Luxus der Relationenverwaltung kann man eigentlich nur innerhalb von EJB-Methoden nutzen


----------



## KISS (16. Jun 2005)

da ich kein dao benutze muss ich vermuten:

kann man die objekte nicht lazy instanziieren? dann hat man zwar rekursion, macht aber nichts.


----------



## Bleiglanz (16. Jun 2005)

jo,

ich denke mal das hibernate / jdo und wie sie alle heissen genau so vorgehen


----------



## timomeinen (16. Jun 2005)

Lazy ist ein guter Einwand. _Composite Pattern_ ist das Schlagwort, oder?


----------



## Bleiglanz (16. Jun 2005)

nein, das Composite Pattern hat damit gar nichts zu tun 

Lazy ist ja auch nichts anderes, als zuerst die Fremdschlüsselwerte festzuhalten und bei bedarf die entsprechenden Datensätze aus der DB zu holen

also oben dein 1. Ausweg

nur eben mit dem Unterschied, dass das "Nachladen" transparent vor sicht geht


----------



## timomeinen (16. Jun 2005)

Also in der DTO stehen keine weiteren DTOs, sondern IDs, richtig?

Wo geschieht denn dann das "lazy loading"? Doch nicht in der DTO, oder?


----------



## Bleiglanz (16. Jun 2005)

tja, das ist das problem: eigentlich schon...

manche O/Rs manipulieren dann den Bytecode, so dass der Anwender davon nix mitkriegt

Client ruft getAllArtikel auf dem DTO auf
dieses merkt, dass die noch nicht geladen sind und holt sie sich usw.

ggf. bräuchte man eine ganze DTO-Fassade (oder gleich EntityFassade), die das alles macht (und die DTOs haben dann eine Referenz auf diese usw....)

lohnt sich aber nicht, sowas selbst zu verwirklcihen


----------



## timomeinen (16. Jun 2005)

Also der Ansatz DAO-Aufrufe aus einer DTO heraus zu machen ist nicht schön. Das wiederspricht auch dem Ansatz, dass DTOs dazu da sind Daten zu transportieren.

Ich denke, das einfachste wird sein, nur die IDs zu speichern und dann in der Geschäftslogik einen weiteren DAO-Aufruf durchzuführen.

Timo


----------



## Guest (20. Jul 2005)

timomeinen hat gesagt.:
			
		

> Also der Ansatz DAO-Aufrufe aus einer DTO heraus zu machen ist nicht schön. Das wiederspricht auch dem Ansatz, dass DTOs dazu da sind Daten zu transportieren.
> 
> Ich denke, das einfachste wird sein, nur die IDs zu speichern und dann in der Geschäftslogik einen weiteren DAO-Aufruf durchzuführen.
> 
> Timo


Wie wäre es mit einer Art ConnectorFactory (ConnectorRegistry), die anhand der Klasse 
eines Objekts einen entsprechenden Connector zurückgibt, über den man dann auf die 
"related records" zugreifen kann. 
z.B.
	
	
	
	





```
...
Connector<Bestellposition> con = (Connector<Bestellposition>)ConnectorFactory.getConnectorInstance(Bestellposition.class);
Collection<Bestellposition> bestellPositionen = con.getAllByReferenceList(referenceList);
...
```
Jeder Connector fungiert dann als ein Clientside-Proxy, so dass die ganzen DTO's reine 
Transportobjekte bleiben. Ein Connector übernimmt den Zugriff auf die Persistenzschicht 
und die Konvertierung der DTO's, Referenzen etc. in die clientseitige Präsentation der Daten
und umgekehrt. 
Vorteil: Einheitliche Schnittstellen, Zugriff auf die Persistenzschicht bleibt dem Client verborgen,
alles lässt sich sicher anhand des ERM einfach generieren.

Hmm...sicher gibt es sowas bereits... kann mich einer einweisen?


----------

