# JPA Joins



## DeviAn (8. Sep 2009)

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?


----------



## maki (8. Sep 2009)

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?

```
SELECT * FROM TABELLE1 JOIN TABELLE2 ON TABELLE1.id = TABELLE2.id
```


----------



## DeviAn (8. Sep 2009)

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  )) zu Joinen.


----------



## maki (8. Sep 2009)

> 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 (8. Sep 2009)

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....


----------



## SlaterB (8. Sep 2009)

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


----------



## maki (8. Sep 2009)

> 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 (8. Sep 2009)

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?


----------



## maki (8. Sep 2009)

> 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.


----------



## DeviAn (8. Sep 2009)

Was is denn der unterschied zwischen 
Entitys und Entites????


----------



## maki (8. Sep 2009)

Entities = plural von Entity

Die hast du immer noch nicht gezeigt


----------



## DeviAn (8. Sep 2009)

also Entity 1:


```
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:


```
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.


----------



## DeviAn (8. Sep 2009)

weiß denn niemand wie man das macht?


----------



## maki (8. Sep 2009)

> 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?


----------



## DeviAn (8. Sep 2009)

Naja so halb. War dabei und bin dann bei demm Problem stehen geblieben...


----------



## maki (8. Sep 2009)

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

Wo genau hängst du denn?


----------



## DeviAn (9. Sep 2009)

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


----------



## maki (9. Sep 2009)

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


----------



## DeviAn (9. Sep 2009)

Na gut. Hast recht eine glas kugel hat nich jeder. :lol:
Also Entity1:

```
//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

```
//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:

```
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:


```
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:

```
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


----------



## maki (9. Sep 2009)

```
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 (10. Sep 2009)

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


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

die Exception:


```
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 (10. Sep 2009)

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

Vorher:


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


Nachher:

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

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


----------



## maki (10. Sep 2009)

> 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.


----------



## DeviAn (10. Sep 2009)

Hmm könntest du mir ganz kurz den unterschied zwischen eager und Lazy erklären?


----------



## maki (10. Sep 2009)

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 (10. Sep 2009)

Axso. Allet klar jetzt ha ichs kappiert.

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


```
WHERE LOWER(FIRSTNAME) = LOWER('HeInZ')
```

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


----------



## maki (10. Sep 2009)

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


----------



## DeviAn (10. Sep 2009)

Ja stimmt, so kann ich das 


```
LOWER('HeInZ')
```

hinbekommen.

Aber das 


```
LOWER(FIRSTNAME)
```

??

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


----------



## DeviAn (10. Sep 2009)

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


----------

