Aufbau JPA Projekt

Status
Nicht offen für weitere Antworten.
Hallo zusammen,

wie baut man am Besten ein größeres JPA Projekt auf? Ich würde das so machen:

An unterster Stelle stehen die Entity-Beans, die die physikalischen Tabellen in der Datenbank reprästentieren:

Java:
@Entity
@Table(name = "test_tbl")
public class Test extends BaseEntity {

  @Id
  private Long id;

  @Column(name = "string_column");
  private String stringColumn;

  // ...
}

Anschließend folgen die DAOs. Diese beinhalten den EntityManager und speichern die Named(Native)Querys, was mich gleich zur nächsten Frage bringt: Wie kommt der EntityManager in das DAO und wo sollten die Querys gespeichert werden?

Java:
public class TestDAO {

  private static final String FIND_ALL = "project.Test.findAll";

  // Wie kommt der ins DAO?
  private EntityManager entityManager;

  public List<Test> findAll() {
    // Woher kommt der NamedQuery? Aus einer XML? Aus einer Datei? Als Annotation direkt am DAO?
    Query query = entityManager.createNamedQuery(FIND_ALL);
    @SuppressWarnings("unchecked")
    List<Test> list = query.getResultList();
    return list;
  }

}

Ich würde für jede Entity ein eigenes DAO anlegen. Ist das soweit die korrekte Vorgehensweise? Was mache ich, wenn Abfragen über mehrere Entitys notwendig sind, die keiner Entity zuzuordnen sind? Ein "NoEntityDAO"?

Jetzt kommt bei mir die Handler-Schicht (Business-Logik). Ein Handler kann mehrere DAOs beinhalten und daraus Methoden aufrufen. Er kümmert sich bspw. um alle Stammdaten (die ja auf mehrere DAOs und Entitys verteilt sein können). Aus den Ergebnissen der Methode baut er ein Business-Object, welches dann weiter nach oben gereicht wird. Ist das soweit üblich? Und wie kommen die DAOs in den Handler? Einfach über "new" instanziieren? Oder mit einem Singleton?

Java:
public class SomeDataBO extends BaseBO {

  private String value1;
  private String value2;

  // Getter und Setter
}

Java:
public class MasterDataHandler {

  // Wie komme ich hier an die DAOs?
  private TestDAO testDAO;
  private OtherDAO otherDAO;

  public SomeDataBO findSomeData(boolean aFlag) {

    SomeDataBO sdb = new SomeDataBO();
    sdb.setValue1(testDAO.getValue());
    sdb.setValue2(otherDAO.getValue(aFlag));
    return sdb;
  }
}

Diese Handler werden dann von Fassaden aufgerufen, welche die eigentlichen Beans darstellen. Eine Fassade hat Zugriff auf mehrere Handler und macht eigentlich nichts weiter, als eine einzelne Handler-Methode aufzurufen. Eine Fassade ist für die Belieferung eines zusammenhängenden Programmteils (bspw. eine GUI Maske) zuständig. Auch hier meine Frage: Ist das so in Ordnung? Wie komme ich an die Instanzen der Handler? So wie bei den DAOs?

Java:
@Local
@Remote
@Stateless(name = "CoolFacade")
@TransactionManagement(TransactionManagementType.CONTAINER)
public class CoolFacade extends BaseFacade implements ICoolFacade {

  // Wie kommt der MasterDataHandler in die Bean?
  private MasterDataHandler masterDataHandler;

  public SomeDataBO findSomeData(boolean aFlag) {
    return masterDataHandler.findSomeData(aFlag);
  }
}

So, ich hoffe, ich habe jetzt nichts vergessen. Ansonsten dürft ihr mich jetzt gerne in der Luft zerreisen ;) .

Danke!
 
M

maki

Gast
An unterster Stelle stehen die Entity-Beans, die die physikalischen Tabellen in der Datenbank reprästentieren:
Das ist richtig, allerdings sollte die id ein [c]long[/c] und kein [c]Long[/c] sein.

Wie kommt der EntityManager in das DAO
Nutzt du Spring oder EJB3?

und wo sollten die Querys gespeichert werden?
Entweder in die Daos, oder die Entities, oder in eine ganz eigene Klasse die nix anderes macht als Quieres zu halten.
Wenn du Repositories anstatt Daos nutzt, wäre das der Ort für die Queries.

Ich würde für jede Entity ein eigenes DAO anlegen. Ist das soweit die korrekte Vorgehensweise? Was mache ich, wenn Abfragen über mehrere Entitys notwendig sind, die keiner Entity zuzuordnen sind? Ein "NoEntityDAO"?
Naja, nicht jede Entity muss über ein Dao erreichbar sein, manchmal reicht es schon wenn man durch traversieren einer Entitiy eine andere findet.
Ansonsten solltest du imho die Query-Methoden nach Rückgabewerten auf die Daos oder Repositories verteilen, wenn eine Query User Objekte zurückgibt, ist das UserDao bzw. UserRepository der richtige Ort dafür.

Jetzt kommt bei mir die Handler-Schicht (Business-Logik). Ein Handler kann mehrere DAOs beinhalten und daraus Methoden aufrufen. Er kümmert sich bspw. um alle Stammdaten (die ja auf mehrere DAOs und Entitys verteilt sein können). Aus den Ergebnissen der Methode baut er ein Business-Object, welches dann weiter nach oben gereicht wird. Ist das soweit üblich?
Weiss zwar nicht was du miut "oben" meinst, aber das nennt sich TranscctionScript was du beschreibst: P of EAA: Transaction Script

Und wie kommen die DAOs in den Handler? Einfach über "new" instanziieren? Oder mit einem Singleton?
Singletons solltest du vermeiden, macht den Code nur sehr umständlich testbar, so wie alle festverdrahteten Abhängigkeiten.
Wie bereits gefragt, willst du EJB3 nutzen oder Spring? ;)

Gibt es einen Grund warum du die Facade von den Handlern trennst?
 

velaluka

Aktives Mitglied
Das ist richtig, allerdings sollte die id ein long und kein Long sein.
Warum sollte es der Primitive Typ sein? Wie sieht es bei Assoziationen mit einer Kardinalität 0..1 aus. Wie kann ich dann ein Null Value für die Fremdschlüssel Id setzen?
 
M

maki

Gast
Warum sollte es der Primitive Typ sein? Wie sieht es bei Assoziationen mit einer Kardinalität 0..1 aus. Wie kann ich dann ein Null Value für die Fremdschlüssel Id setzen?
Assoziationen mit der Kardinalität 0..1 auf eine Zahl?
Wir sprechen hier von der ID, schon klar oder? ;)
 

velaluka

Aktives Mitglied
Natürlich sprechen wir hier nicht nur von einer Zahl ;-) sondern von einer Id. Es könnte doch aber sein, dass man eventuell mal ein Null hinterlegen will, weil es noch keine assoziiertes Objekt gibt.
Meine frage wäre dann:
Wie mache ich das wenn die id ein long Typen hat?
Und meine Fremdschlüssel möglichst den gleichen Typen haben soll....
 
Zuletzt bearbeitet:
M

maki

Gast
Natürlich sprechen wir hier nicht nur von einer Zahl ;-) sondern von einer Id. Es könnte doch aber sein, dass man eventuell mal ein Null hinterlegen will, weil es noch keine assoziiertes Objekt gibt.
Meine frage wäre dann:
Wie mache ich das wenn die id ein long Typen hat?
Verstehe deine Frage ehrlich gesagt nicht.

Die eigene ID ist nur "leer", wenn die Entity noch transient, also noch nicht persistent ist.
Die JPA Implementierung sorgt dafür, dass die befüllt wird sobald die Entity persistiert wird.
Wie du da auf assozierte Objekte kommst ist mir schleierhaft...
 
Hi, danke für die schnelle Antwort!

Nutzt du Spring oder EJB3?

EJB3 (die Spring Lösung würde mich aus Wissensdurst aber auch interessieren)

Entweder in die Daos, oder die Entities, oder in eine ganz eigene Klasse die nix anderes macht als Quieres zu halten.

Heißt: Es ist relativ egal, wo die Querys stehen und es gibt keine "Standards"!?

Wenn du Repositories anstatt Daos nutzt, wäre das der Ort für die Queries.

Was versteht man/Was sind hier unter Repositories?

Naja, nicht jede Entity muss über ein Dao erreichbar sein, manchmal reicht es schon wenn man durch traversieren einer Entitiy eine andere findet.

Sorry, das habe ich vergessen zu erwähnen: Natürlich nur für Entities, die direkt abgefragt werden ein extra DAO.

Ansonsten solltest du imho die Query-Methoden nach Rückgabewerten auf die Daos oder Repositories verteilen, wenn eine Query User Objekte zurückgibt, ist das UserDao bzw. UserRepository der richtige Ort dafür.

Das ist eine sehr gute Idee. Aber wenn ich jetzt bspw. von einem Query mehrere Entities und/oder Entitiy-Values zurück geben lasse, wohin dann damit?

Weiss zwar nicht was du miut "oben" meinst, aber das nennt sich TranscctionScript was du beschreibst: P of EAA: Transaction Script

"oben" wäre in meinem Fall die nächste Schicht: an die Fassaden bzw. die aufrufenden Klassen/Objekte. Den Link werde ich mir auf jedenfall mal ansehen, danke!

Gibt es einen Grund warum du die Facade von den Handlern trennst?

Hab das gerade noch einmal mit meinem Kollegen besprochen. Man könnte hier tatsächlich eine Schicht einsparen. War einfach ein Designfehler. Danke für den Hinweis!
 
M

maki

Gast
EJB3 (die Spring Lösung würde mich aus Wissensdurst aber auch interessieren)
Die beiden Lösungen funktionieren im Prinzip gleich: es wird per DependencyInjection injiziert, in EJB nimmt man dafür die @PersistenceContext Annotation für den EntityManager, in Spring die @Resource oder @Autowire Annotation, oder in der XML Konfiguration.

Heißt: Es ist relativ egal, wo die Querys stehen und es gibt keine "Standards"!?
"Industriestandards" gibt es dafür keine...
Sinnnvoll sollte es sein, und da sich "sinnvoll" ja nach Anwendungsfall unterscheidet, musst du diese Entscheidung treffen ;)

Was versteht man/Was sind hier unter Repositories?
Repositories sind Daos, aber anders als DAOs sind sie Teil des Domainmodells und damit der Businessschicht, es ist im Prinzip egal ob man sie Repostories oder Daos nennt, allerdings landet immer wieder Businesslogik in DAOs/Repositories, mit Daos wäre das ein Bruch der Trennungskonzeptes, weil Daos eben teil der Persistenzschicht sind.

Das ist eine sehr gute Idee. Aber wenn ich jetzt bspw. von einem Query mehrere Entities und/oder Entitiy-Values zurück geben lasse, wohin dann damit?
Da wo sie am besten hinpassen ;)
So etwas macht man imho übrigens eher für Reports, ich kenne dass so das ein Dao eine einzelne Entity oder eine Collection von der gleichen Entity zurückgibt.

Den Link werde ich mir auf jedenfall mal ansehen, danke!
Leider steht da nicht allzuviel, Martin Fowler wollte nicht sein ganzes Buch PEAA online stellen, im Buch wird genauer darauf eingegangen.
 
Die beiden Lösungen funktionieren im Prinzip gleich: es wird per DependencyInjection injiziert, in EJB nimmt man dafür die @PersistenceContext Annotation für den EntityManager, in Spring die @Resource oder @Autowire Annotation, oder in der XML Konfiguration.

Dann kann das DAO aber nur kein PoJo sein, sonst ist der EntityManager = null. Was ist ein DAO dann sinnvollererweise?

Repositories sind Daos, aber anders als DAOs sind sie Teil des Domainmodells und damit der Businessschicht, es ist im Prinzip egal ob man sie Repostories oder Daos nennt, allerdings landet immer wieder Businesslogik in DAOs/Repositories, mit Daos wäre das ein Bruch der Trennungskonzeptes, weil Daos eben teil der Persistenzschicht sind.

Gut, das wir bei uns eigentlich vermieden (und falls nicht, bekommt der jenige auf die Finger ;) ).

Da wo sie am besten hinpassen ;)
So etwas macht man imho übrigens eher für Reports, ich kenne dass so das ein Dao eine einzelne Entity oder eine Collection von der gleichen Entity zurückgibt.

Klingt sinnvoll, aber Reports? Wie schaut sowas denn wieder aus :oops: ?
 
M

maki

Gast
Dann kann das DAO aber nur kein PoJo sein, sonst ist der EntityManager = null. Was ist ein DAO dann sinnvollererweise?
Bin über die Details nicht informiert, aber sollten seit EJB3.1 nicht auch "nicht-SessionBeans" injizierbar sein?

Gut, das wir bei uns eigentlich vermieden (und falls nicht, bekommt der jenige auf die Finger ).
Hmmm... ist bis jetzt immer passiert sobald DAOs genutzt wurden, wird von den meisten ignoeriert, aber echte DAOs ganz ohne BusniessLogik kenne ich eigentlich nicht...

Klingt sinnvoll, aber Reports? Wie schaut sowas denn wieder aus
Ach, was ich meinte war das Daos eigentlich so gut wie nie eine Collection mit mehreren Entites zurückgeben ;)
 
Und wie kommen die DAOs in den Handler? Einfach über "new" instanziieren? Oder mit einem Singleton?

Das Problem besteht übrigens auch noch, nicht dass mir das in Vergessenheit gerät ;) .

Bin über die Details nicht informiert, aber sollten seit EJB3.1 nicht auch "nicht-SessionBeans" injizierbar sein?

Und bei EJB 3.0?

Hmmm... ist bis jetzt immer passiert sobald DAOs genutzt wurden, wird von den meisten ignoeriert, aber echte DAOs ganz ohne BusniessLogik kenne ich eigentlich nicht...

Ja gut, das ist dann aber unser Problem. Danke soweit!

Ach, was ich meinte war das Daos eigentlich so gut wie nie eine Collection mit mehreren Entites zurückgeben ;)

Und wenn es Ausnahmefälle gibt, wo sie es doch tun? Bspw. bei einem nativen SQL, der nicht auf eine Entity gemapped werden kann, da er aus mehreren Entitys zusammen besteht (wäre dann ein
Code:
List<Object[]>
)

Auf jedenfall schon mal vielen herzlichen Dank! Langsam kommt Licht ins Dunkel :) .
 
M

maki

Gast
Das Problem besteht übrigens auch noch, nicht dass mir das in Vergessenheit gerät
Schon klar, aber wie gesagt, EJB3.1 sollte das doch gelöst haben, oder etwa nicht?

Schaut man mit dem Ofenrohr ins Gebirge.. ;)
Mal ernsthaft, wenn es keine "ausreichende" DI gibt, muss man wohl wieder zum Resourcelookup zurückgehen, mit allen dazugehörigen Nachteilen... hab schon gesehen dass Leute ihre DAOs als stateless SessionBeans Annotiert haben um dieses Problem zu umgehen, finde ich nicht so dolle.
Würde ehrlich gesagt EJB3.1 anstatt EJB3.0 nutzen, falls irgendwie möglich.

Und wenn es Ausnahmefälle gibt, wo sie es doch tun? Bspw. bei einem nativen SQL, der nicht auf eine Entity gemapped werden kann, da er aus mehreren Entitys zusammen besteht (wäre dann ein List<Object[]> )
In Ausnahmefällen gibt es eben Ausnahmen, muss dann aber für den Fall passen ;)
Vielleicht ein eigenes DAo, vielleciht passend sie thematisch in ein bereits bestehendes, kommt immer darauf an.
 
M

maki

Gast
@velaluka

Meine Aussage bez. des Typs der ID war falsch.

Hattest Recht, die ID sollte schon ein [c]java.lang.Long[/c] sein, sonst gibt es sehr viele Objekte mit der id 0 ...:oops:
 
Hallo nochmal!

Sorry, bin leider nicht früher dazu gekommen zu Antworten.

Ich denke, es sollte jetzt alles soweit klar sein. Danke an alle und auch noch einmal an die Korrektur mit der ID :) .
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen


Oben