JPA Joins

Status
Nicht offen für weitere Antworten.

DeviAn

Mitglied
Hallo Forum,

ich habe gerade frisch mit JPA angefangen und hab es jetzt auch geschaft mein erstes
SELECT * FROM TABELLE
in JPA zu realisieren.

Mein Problem ist jetzt wie ich ein JPA Statment ala:
SELECT * FROM TABELLE1 JOIN TABELLE2 ON TABELLE1.id = TABELLE2.id

mache. Hab dazu viel gefunden bei google, aber leider nix verstanden...

Kan mir wer helfen?
 
M

maki

Gast
Suche mal nach JPAQL.

Welche JPA Implementierung verwendest du denn?

Darf man fragen wozu das gut sein soll bzw. was du mit so einer Query erreichen möchtest?
Code:
SELECT * FROM TABELLE1 JOIN TABELLE2 ON TABELLE1.id = TABELLE2.id
 

DeviAn

Mitglied
hi,

danke erstmal für die schnelle Antwort.
Also erstmal: Was meinst du mit "JPA implementierung". Übern daumen glaub ich willst du da EclipseLink höhren oder? :)

2. Also das statement ist einfach mal nur ein bsp. ich versuche überhaupt irgendwie Tabellen in JPA(wo bei das ja JPAQL heisst (wieder was gelernt :D )) zu Joinen.
 
M

maki

Gast
Also erstmal: Was meinst du mit "JPA implementierung". Übern daumen glaub ich willst du da EclipseLink höhren oder?
Eigentlich will ich hören welche JPA Implementierung du nutzt ;)
Hibernate, EclipseLink, Datanucleus...
Also du nutzt EclipseLink.

2. Also das statement ist einfach mal nur ein bsp. ich versuche überhaupt irgendwie Tabellen in JPA(wo bei das ja JPAQL heisst (wieder was gelernt )) zu Joinen.
Man muss sich auch fragen, ob das Sinne rgibt was man da versucht, ein ORM ist kein RDBMS, es gibt Fetch joins, die haben aber andere funktionalitäten als du gerade annimmst.

Du schreibst doch zu deinen Attributen die Mappinginformationen, oder?
Welchen Sinn sollte es dann haben, diese Mappinginfos dann nochmal per Hand in eine Query zu schreiben?
Alles in allem solltest du mehr mit Objekten denken anstatt mit Tabellen.
 

DeviAn

Mitglied
Ach mensch warum muss man das so kompliziert machen ??? ;(;(;(

Also prinzipiel ist es mir egal wie das JPAQL aussieht. Am ende will ich nur ein entity raus haben, in dem
a. die daten aus Tabele1
b. die daten aus Tabele2

stehen....
 
S

SlaterB

Gast
SELECT * FROM TABELLE1 t, TABELLE2 u where t.id = u.id

höhere Joins wie LEFT JOIN sind so aber nicht möglich,
wenn da keine Mapping-Beziehung besteht, sieht man alt aus,
zumindest in Hibernate
 
M

maki

Gast
Ach mensch warum muss man das so kompliziert machen ???
Du machst die Sache komplizierter als nötig, weil du dich anscheinend noch nicht genug in JPA bzw ORM allgemein eingelesen hast...

Also prinzipiel ist es mir egal wie das JPAQL aussieht. Am ende will ich nur ein entity raus haben, in dem
a. die daten aus Tabele1
b. die daten aus Tabele2
Ist doch Quatsch, was du willst sind Entities.

Du stelltst immer noch die falschen Fragen ;)

Nehmen wir mal an, du hast Entity A und Entity B, A hat eine 1:1 Relation zu B.
Wenn du nun A lädst, wird auch B mitgeladen (vereinfacht ausgedrückt), die Joins kommen automatisch, eigene Fetch Joins zu schreiben macht erst Sinn, wenn du den Unterschied zwischen Lazy und Eager loading verstanden hast.
 

DeviAn

Mitglied
so maki jetzt hast es geschafft: jetzt bin ich vollends verwirtt ???:L???:L???:L

Ich versuchs mal so zu fragen was muss ich machen wenn ich in ein Entitie haben will in dem Alle daten aus Tabele A und B passend zueinander drin stehen?

Tabelle A:
Feld1= Person_ID
Feld2= Vorname
Feld3= Nachname

Tabele B:
Feld1= Address_ID
Feld2= fuer_Person_ID
Feld3= volleAddresse

In SQL würde das ganz schnell gehen:
SELECT * FROM A LEFT JOIN B ON A.Person_ID = B.fuer_person_id

damit krieg ich alles aus A und B, auch wenn in B dazu nix steht.
Und die sachen will ich hal in einem Entitie drin haben.

Verstehst wie ich mein?
 
M

maki

Gast
o maki jetzt hast es geschafft: jetzt bin ich vollends verwirtt
Verwirrt warst du schon vorher, damit hab ich nix zu tun, deswegen stellst du immer noch die falschen Fragen...

Ich hör immer nur Tabellen & Felder, du solltest nach Klassen bzw. Objekten und Instanzvariablen fragen.

Und die sachen will ich hal in einem Entitie drin haben.
Zuerst kommt die Entites, die Queries werden dann automatisch erzeugt für die einfachen Fälle.

Verstehst wie ich mein?
Ja, aber du meinst das falsche ;)
Oder meinst du NativeQueries? Glaub ich jetzt mal nicht.
 
M

maki

Gast
Entities = plural von Entity

Die hast du immer noch nicht gezeigt ;)
 

DeviAn

Mitglied
also Entity 1:

Java:
import java.io.Serializable;
import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;



@Entity
@Table( name = "PERSONEN" )

public class PersonEntity implements Serializable {
	private static final long serialVersionUID = 1L;
	
	@Id
	@Column(name = "PERSONEN_ID")
	private Integer persID;

	@Column(name = "VORNAME")
	private Integer vorName;

	@Column(name = "NACHNAME")
	private String nachName;
    
        //und halt die Getter und Setter
}


und die 2 Entity:

Java:
import java.io.Serializable;
import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;



@Entity
@Table( name = "ADDRESSE" )

public class AddressEntity implements Serializable {
	private static final long serialVersionUID = 1L;
	
	@Id
	@Column(name = "ADDRESS_ID")
	private Integer addressID;

	@Column(name = "FUER_PERSONEN_ID")
	private Integer fuerID;

	@Column(name = "ADDRESSE")
	private String addresse;
    
        //und halt die Getter und Setter
}

so und die zwei möcht ich jetzt in einer Entity zusammen gefasst haben.
 
M

maki

Gast
so und die zwei möcht ich jetzt in einer Entity zusammen gefasst haben.
Na also, so kommen wir doch noch voran :)

Dir fehlen die Mappings zwischen PersonEntity und AddressEntity.
Entweder eine @OneToOne Relation (eine Addresse pro Person), oder eine @ManyToOne Relation (eine Addresse für mehrere Personen).
Den Rest macht dann EclipseLink automatisch.

Schon ein JPA/EclipseLink Tutorial durchgearbeitet?
 
M

maki

Gast
Wenn du die Mappings vervollständigst, hast du doch schon was du brauchst.

Wo genau hängst du denn?
 

DeviAn

Mitglied
Also ein "einfaches" OneToOne hab ich mittlerweile hinbekommen.
Jetzt häng ich allerdings an nem OneToMany...
 
M

maki

Gast
Wenn du uns jetzt noch den Code zeigen würdest, könnten wir Versuchen den Fehler zu finden ;)
 

DeviAn

Mitglied
Na gut. Hast recht eine glas kugel hat nich jeder. :lol:
Also Entity1:
Java:
//imports
@Entity
@Table( name = "WF_EMPLOYEES" )
public class IsBossEntity implements Serializable {
	private static final long serialVersionUID = 1L;
	
	@Id
	@Column(name = "EMP_ID")
	private Integer empID;

	@Column(name = "EMAIL_ADDRESS")
	private String eMail;

	@Column(name = "COSTCENTER_ID")
	private Integer costID;
	
	@OneToMany(mappedBy="vorgesetzterEmp")
	private Set<CostCenterEntity> manageCostCenters;


        //Getter und Setter Methoden

}

Entity2
Java:
//imports

@Entity
@Table(name = "WF_COSTCENTER")
public class CostCenterEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@Column(name = "COSTCENTER_ID")
	private Integer costCenterID;

	@Column(name = "COSTCENTER_NAME")
	private String costCenterName;
	
	@ManyToOne
	@JoinColumn(name = "VORGES_EMP_ID")
	private IsBossEntity vorgesetzterEmp;

        //Getter und Setter Methoden

}

hier noch das JPAQL:
Java:
public List getResult() {
		
		Query q = manager.createQuery("SELECT boss FROM IsBossEntity boss JOIN FETCH boss.manageCostCenters WHERE boss.eMail = :eMail");
		q.setParameter("eMail", "user@email.com");
		List results = q.getResultList();
		
		return results;
		/*
		 * EntityTransaction tx = manager.getTransaction(); tx.begin(); DBTest
		 * test = new DBTest(); manager.persist(test); tx.commit();
		 * System.out.println("Fertig");
		 */
	}

so wenn ich jetzt an anderer stelle die List wieder auseinander nehme:

Java:
private static void testJPA() {
		CostCenterServiceRemote s = BeanLocator.lookup(
				CostCenterServiceRemote.class, "ejb/CostCenterServiceRemote");
		List result = s.getResult();

		Iterator resultIterator= result.iterator();
		while (resultIterator.hasNext()) {
			IsBossEntity cost = (IsBossEntity) resultIterator.next();
			Iterator<CostCenterEntity> costIterator= cost.getManageCostCenters()
					.iterator();
			while (costIterator.hasNext()) {
				System.out.println(costIterator.next().getCostCenterName());
			}
			System.out.println(cost.getEMail());
		}

		System.out.println("Hab wes :)");
	}

so witziger weiße bekome ich 5x dass hier ausgegeben:
Code:
Abt1
Abt2
Abt3
Abt4
Abt5
user@email.com

Ich versteh einfach net warum das so ist. die daten stimmen ja ansich. nur warum ist das result 5 mal vorhanden ???:L???:L???:L
 
M

maki

Gast
Code:
JOIN FETCH boss.manageCostCenters
Lass das weg.

Wie gesagt, Fetch Joines haben in JPAQL eine andere Funktion als Joins in SQL.

Da du die Metainformationen über die Beziehungen von Entitäten bereits im Mapping mitangibst, brauchst du diese nicht extra in Queries mitangeben.
JOIN FETCH hilft die Performance zu steigern, wenn man die Entities auf eine andere VM serialisiert stellt man damit sicher dass die referenzierten Entities bereits geladen sind, letzteres ist für dich im Moment nicht relevant, ersteres klannst du auch ignorieren, also lass es weg ;)
 

DeviAn

Mitglied
Aber wenn ich das "JOIN FETCH" weg lasse bekom ich von der Zeile:

Java:
Iterator<CostCenterEntity> setPup = cost.getManageCostCenters().iterator();

die Exception:

Java:
Exception in thread "main" Local Exception Stack: 
Exception [EclipseLink-7242] (Eclipse Persistence Services - 1.1.1.v20090430-r4097): org.eclipse.persistence.exceptions.ValidationException
Exception Description: An attempt was made to traverse a relationship using indirection that had a null Session.  This often occurs when an entity with an uninstantiated LAZY relationship is serialized and that lazy relationship is traversed after serialization.  To avoid this issue, instantiate the LAZY relationship prior to serialization.
	at org.eclipse.persistence.exceptions.ValidationException.instantiatingValueholderWithNullSession(ValidationException.java:954)
	at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:219)
	at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:83)
	at org.eclipse.persistence.indirection.IndirectSet.buildDelegate(IndirectSet.java:192)
	at org.eclipse.persistence.indirection.IndirectSet.getDelegate(IndirectSet.java:343)
	at org.eclipse.persistence.indirection.IndirectSet$1.<init>(IndirectSet.java:410)
	at org.eclipse.persistence.indirection.IndirectSet.iterator(IndirectSet.java:409)
	at Main.listScims(Main.java:32)
	at Main.main(Main.java:11)
 

DeviAn

Mitglied
Ahhh ich habs raus bekommen. Mann muss noch den FetchType setzen.

Vorher:

Java:
@OneToMany(mappedBy="vorgesetzterEmp")
	private Collection<CostCenterEntity> manageCostCenters;


Nachher:
Java:
@OneToMany(mappedBy="vorgesetzterEmp",fetch=FetchType.EAGER)
	private Collection<CostCenterEntity> manageCostCenters;

Aber warum das so ist weiß ich net. Hat da jemand ne idee???
 
M

maki

Gast
Aber wenn ich das "JOIN FETCH" weg lasse bekom ich von der Zeile:
Ok, wenn du die Sesion schliesst und mit der Entity weiterarbeiten möchtest, brauchst du den Fetch Join auch.

Wie sehen denn die Daten in der DB aus?
Hast du Null Werte in dem Feld VORGES_EMP_ID?

Wenn du in der persistence.xml folgende Property setzt:
[xml] <property name="eclipselink.logging.level" value="FINE"/>[/xml]
.. siehst du die generierten SQL Statements.

Aber warum das so ist weiß ich net. Hat da jemand ne idee???
Klar, eager vs. lazy fetching, alternativ kann man Lazy Relationen auch über die Fetch Joins eager laden lassen.
 
M

maki

Gast
Eager heisst dass diese Objekt immer mitgeladen wird, Lazy dass das Objekt nur geladen wird, wenn darauf zugegriffen wird, dazu sollte aber die Session offen sein, sonst gibt es die Exception.
 

DeviAn

Mitglied
Axso. Allet klar jetzt ha ichs kappiert.

Kleine Frage am rande: Wenn ich das im SQL so mache:

SQL:
WHERE LOWER(FIRSTNAME) = LOWER('HeInZ')

Wie mach ich das dann in JPAQL? Oder mach ich das auch direkt im Entity?
 
M

maki

Gast
String kennt die Methoden toLowerCase() und toUpperCase(), lässt sich also in Java bereits umwandeln.
 

DeviAn

Mitglied
Ja stimmt, so kann ich das

SQL:
LOWER('HeInZ')

hinbekommen.

Aber das

SQL:
LOWER(FIRSTNAME)

??

Ich kann mir so garnicht vorstellen wie das gehen soll...
 

DeviAn

Mitglied
Ahh sry ich hätte vorher googeln sollen und nicht danach :)

Mann kann wohl das LOWER() auch im JPAQL auch benutzen gleich wie in SQL
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen


Oben