PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : EJB3 1:n-Relationen



ComSubVie
06-12-2006, 08:01
Ich hab mir (in Anlehnung an das Buch "Enterprise Java Beans 3.0") mal eine einfache Testapplikation gebaut. Der gesamte Source findet sich auf http://markus.ocrs.at/2006/12/05/ejb3-proof-of-concept (incl. c#-Democlient)

Es gibt 2 Entities: eine Cruise und eine Reservation, wobei eine Cruise beliebig viele Reservations haben kann:

@Entity
public class Reservation implements java.io.Serializable {
private Cruise cruise;

@ManyToOne
@JoinColumn( name = "CRUISE_ID" )
public Cruise getCruise() {
return cruise;
}


@Entity
public class Cruise implements java.io.Serializable {
private Collection reservations = new ArrayList();

@OneToMany( mappedBy = "cruise" )
public Collection getReservations() {
return reservations;
}
Prinzipiell funktioniert das ja ganz gut, was ich nicht verstehe, ist warum eine Suche nach allen Reservierungen die eine bestimmte Cruise betreffen nicht auf die triviale Art geht:

Collection<Reservation> results = cruise.getReservations();
Sondern ich das umständlich über ein Query lösen muss (und die Ergebnisse dann wieder in Reservations umcasten muss):

Query query = em.createQuery( "FROM Reservation r WHERE r.cruise.id=:cruiseID" );
query.setParameter( "cruiseID", cruise.getId() );
List results = query.getResultList();
Gibt es dafür irgendeinen Grund, sollte getReservations() gehen und ich bin zu blöd, oder soll das eh nicht gehen (und warum?)?

Waxolunist
06-12-2006, 09:51
Durch die Tags erzeugst du jede Menge Code im Hintergrund. Das ganze wird dann ähnlich einer DB oder wenn im Container so konfiguriert in einer DB gespeichert ist aber nicht sehr durchsichtig. Das kommt auf den Persistence Provider an. Am besten macht sich hier wahrscheinlich Hibernate. Das ist aber eines der Probleme von EJB3. Denn die DB wird dadurch nicht wirklich besser wartbar, du ersparst dir imho nur ein bisschen SQL und schreibst dafür aber vier mal so lang am Javateil. Und wenn was nicht geht, ist es beinahe unmöglich, das zu debuggen, weil es zumeist nur an einer Konfigurationsdatei liegt, wenn es nicht funktioniert.

Imho solltest du, wenn du nicht unbedingt EJB machen musst, POJOS (Plain Old Java Objects) verwenden, mit einer Anbindung an eine DB als Persistenzschicht (auch DAO genannt). Da wird dann vieles klarer. So machen das auch viele Firmen bei ihren Webapplikationen. Zudem, wenn du diese geschickt aufbaust, erparst du dir viel Programmierarbeit und der Code wird wartbarer und lesbarer.

Für diese Pojos gibt es auch Codegeneratoren, die dir so viel Arbeit ersparen, dass du dich um die Persistenzschicht nicht mehr kümmern musst. Such einmal nach DAO-Generatoren im Web, die gibts wie Sand am Meer. Wir haben bei uns in der Firma ein paar schon selbst geschrieben.

PS: Allerdings frage ich mich wie du zu dem Cruise-Object kommst in

Collection<Reservation> results = cruise.getReservations();?

ComSubVie
06-12-2006, 11:02
Ich dachte Entitäten in EJB3 sind POJOs ;)

Naja, das muss leider EJB3 + Hibernate + Hypersonic (oder wie die JBoss-DB da heißen mag) sein. In 2.1 hab ich das seinerzeit mit XDoclet recht gut hinbekommen, aber das geht für EJB3 nicht mehr, und was die Annotations machen ist mir auch manchmal mehr als schleierhaft. Und dokumentiert ist das ganze überhaupt nicht. Das das debuggen so gut wie unmöglich ist ist mir auch schon aufgefallen ;)

Ich hab eine EJB3-Methode die mir einen Haufen Objekte anlegt. Im WebService hole ich mir dann einfach alle Cruises (findAllCruises()), und iteriere über die Ergebnisse, und mit einem dieser Ergebnisse rufe ich dann findAllReservationsByCruise() auf, das eben entweder einen Query macht (funktioniert), oder von der Cruise die Methode .getReservations() aufruft (liefert nix). Da cruise.getId() ja einen sinnvollen Wert liefert, müsste .getReservations() dies doch eigentlich auch tun, oder?

Waxolunist
06-12-2006, 11:28
Also durch Annotations werden die Classfiles bestimmt nicht wie POJOS kompiliert, ergo nein. (Oder war das eh Ironie? Ich bin in letzter Zeit so Ironieresistent. Liegt wohl am Winter).

Da die Reservations jedoch noch nicht ins Object Cruise geladen wurden, sondern diese erst von der Persistenzschicht geladen werden müssen mittels eines Querys, liefert dir an dieser Stelle ein getReservations allenfalls eine leere Menge zurück. Das ist wie eine DB-Abfrage, select * from cruises. Dann bekommst du auch noch nicht die Reservations, sondern musst erst noch fragen select * from reservations where cruiseid=argument, also 2 Abfragen machen.

Imho ist diese EJB3-Spez, das schlimmste was je aus dieser Ecke kam. Alles nur Theorie, schaut was ich kann. Man imitiert eine DB ohne DB aber irgendwie doch mit DB - na auf alle Fälle weiß das niemand so genau - und das ganze mit Java anstatt SQL. Ich frage mich, wie da richtige Abfragen ausschauen könnten, also mit joins, orders, groups etc. Und Performance-mäßig wird das nie eingesetzt werden in relevanten Bereichen.

ComSubVie
06-12-2006, 11:55
Also soweit ich das verstanden habe, werden die Annotations nur als Metainformationen mitkompiliert, d.h. die Entity ist auch mit Annotations als POJO verwendbar, um die ganze Persistenz und so kümmert sich der Application Server der diese Metainformationen verwendet.

Hurra, ich habs. Bissi deppad, aber was solls. Wenn man vor dem getReservations() die cruise nochmal lädt funktionierts:

Cruise myCruise = em.fetch( Cruise.class, cruise.getId() );
Collection<Reservations> results = myCruise.getReservations();

Ich dachte das Klump wäre so intelligent die Dinge selbstständig zu laden. Aber das kanns ja nicht, ist ja doch nur ein POJO :D

Anmerkung: Ja, ich kann mir auch nicht vorstellen das das irgendwer freiwillig verwendet um damit Geld zu verdienen (höchstens für Schulungen, aber nicht für Applikationen)

Waxolunist
06-12-2006, 12:40
Ah, klingt logisch. Mit einem Query scheint es also wie einer DB-ähnlich (siehe oben) zu funktionieren und ein fetch lädt das komplette Objekt mit Anhang in den Speicher.

Was mich interessieren würde, wenn du gerade dabei bist, könntest du da mal eine kleine Zeitmessung zu diesen beiden Methoden machen.

Sagen wir so, 1000 oder besser 10000 Reservations aus einer Cruise laden - einmal mit Query und einmal mit dem fetch, wie lange die Ausführung dauert. Also einmal wie lange diese Zeilen benötigen:



Query query = em.createQuery( "FROM Reservation r WHERE r.cruise.id=:cruiseID" );
query.setParameter( "cruiseID", cruise.getId() );
List results = query.getResultList();


Und wie lange diese benötigen:



Cruise myCruise = em.fetch( Cruise.class, cruise.getId() );
Collection<Reservations> results = myCruise.getReservations();


Biiiittte, würde mich mal brennend interessieren.

mfg, christian

ComSubVie
06-12-2006, 13:50
Stunden später... :D

Also mit dem query braucht er für 100.000 Reservations im Durchschnitt 8.1 Sekunden, und mit dem getReservations braucht er 10.6 Sekunden. Das persistieren der Reservations dauert dafür *ewig* (77 Sekunden). Aber ok, das Hypersonic ist ja auch keine vernünftige Datenbank... (und Java ist per Definition langsam)

Waxolunist
06-12-2006, 15:09
Also gut 25% langsamer + wahrscheinlich mehr Speicher - das ist ok. Trotzdem sind 10 sekunden für eine Abfrage ohne Ausgabe oder sonst etwas heavy.

Dass das persistieren lange dauert, also 100.000 Datensätze schreiben, da hab ich bei Oracle schon schlimmeres erlebt. Das erschreckt mich weniger.

Und gut programmiert, finde ich Java seit 1.5 gar nicht mehr langsam. Also eine SWT oder Swinganwendung fühlt sich beinahe schon wie eine native Anwendung an.

Aber danke für deine Informationen.

mfg, christian

ComSubVie
06-12-2006, 17:12
Ich finde die 10 Sekunden durchaus auch recht heftig. Vielleicht probiere ich das mal mit einer vernünftigen Datenbank im Hintergrund, wäre interessant wie sich das auswirkt.
Wobei ich keine Ahnung habe was der JBoss so im Hintergrund noch alles treibt. Und der Rechner ist auch nicht mehr unbedingt der schnellste. Trotzdem glaube ich das ein einfaches "SELECT" ein Zehnerpotenzchen schneller wäre...

Ich gebs ja zu, Java erweckt in letzter Zeit wirklich nicht mehr den Eindruck das man zwischen 2 Klicks einen Kaffee holen muss. Aber ich mag Java nicht, also muss ich meine Vorurteile bestätigen wo es nur geht ;)

mwanaheri
06-12-2006, 20:59
Aber ich mag Java nicht, also muss ich meine Vorurteile bestätigen wo es nur geht ;)
Heißer Tipp: Stringvariablen in einer Schleife erzeugen und dann weiter zusammensetzen. Bremst so schön ;-)

Waxolunist
07-12-2006, 10:15
Weißt du was noch bremst?

while(true);

ComSubVie
07-12-2006, 10:19
Das ist ja einfallslos. Wenn schon, dann 2 Threads und einen Deadlock einbauen ;)

vocki72
07-12-2006, 10:26
Hallo @ all user,
ich habe eine Frage zu Java, ich habe mit der Programmiersprache java echt meine schwierigkeiten, wie und wo finde ich Übungsaufgaben zu OOP ???

Desweiteren habe ich eine Frage:

wie kann ich mit Java , Daten auslesen, wenn das Verzeichnis bekannt ist wo die informationen drin stecken, ich aber nicht weiss welche endungen die Programme haben???

besten dank


volker

Waxolunist
07-12-2006, 10:35
Bitte mach dafür einen eigenen Thread auf, dann wird dir eher geholfen.

Dort kannst du mir dann auch gleich erklären was du mit Programme auslesen meinst.

Und wenn ich in Google "Java Tutorial" eingebe bekomme ich 52.800.000 Treffer. Da wird wohl eines für dich auch dabei sein.

Desweiteren solltest du auch immer die Suchfunktion bemühen. Ein paar Threads unter diesem ist der Thread:

Java Einsteiger,.. womit beginnen?
http://www.mrunix.de/forums/showthread.php?t=47556

Da solltest du ebenfalls fündig werden für Einsteiger.

mfg, christian