# [Glassfish EJB] OneToMany geht nicht



## damike (23. Apr 2012)

Hi

Ich hab Glassfish v3 final und hab folgendes Problem mit EclipseLink:


```
@Entity
public class Person implements Serializable
{
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	
	private String name;
	
	@OneToMany(mappedBy = "person", fetch = FetchType.EAGER)
	private List<Hobby> hobbys;

             // getter und setter
}
```


```
@Entity
public class Hobby
{
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;	
	
	private String name;
	
	@ManyToOne
	@JoinColumn
	private Person person;

              // getter und setter
}
```


```
@javax.ejb.Remote
public interface Testing
{
	public void addTestData();
	public List<Person> getTestData();
}
```


```
@javax.ejb.Stateless
public class TestingBean implements Testing
{
	@javax.persistence.PersistenceContext
	private EntityManager entityManager;
	
	public void addTestData()
	{
		Person p = new Person();
		p.setName("KARL");
		entityManager.persist(p);
		
		Hobby h1 = new Hobby();
		h1.setName("h1");
		h1.setPerson(p);
		
		entityManager.persist(h1);				
	}
	
	public List<Person> getTestData()
	{
		TypedQuery<Person> gridQuery = entityManager.createQuery("SELECT e FROM Person e", Person.class);
		return gridQuery.getResultList();
	}
}
```

Das Problem ist jetzt wenn ich mit getTestData am Client die Daten abfrage bekomm ich zwar "KARL" - aber die Hobbies nicht ... Das Eager Load greift nicht ...
Ich hab dann mit JOIN FETCH probiert - geht - aber ich bekomme die Ergebnisse durch das JOIN doppelt :S Verwende MySQL - die Daten werden in die Datenbank korrekt geschrieben ...

Weiß jemand was da falsch rennt?

Danke
LG


----------



## nillehammer (23. Apr 2012)

Du hast hier eine bidirektionale Relation definiert (Person kennt ihre Hobbies, Hobby kennt seine Person). Bei JPA bist Du selbst dafür verantwortlich, dass beide Enden korrekt sind. Adde beim Code für das Hobby noch folgende Zeile:

```
Hobby h1 = new Hobby();
h1.setName("h1");
h1.setPerson(p);
// Die Zeile hier ist neu
person.getHobbies.add(h1);
```
Da es recht nervig sein kann, daran immer zu denken, macht es Sinn, das Update der Enden in einer der Entities abzufrühstücken. Beispielsweise könnest Du einen Konstruktor für Hobby definieren, in dem Du die Person übergibst und im Konstruktor machst du dann das add.

Auch das getHobbies.add ist nicht aus zwei Gründen nicht so schön:
- Sieht einfach doof aus 
- Der getter gibt eine modifiable List zurück
Da wäre es gut, in Person eine public Methode _addHobby_ anzubieten, den normalen getter _getHobbies_ package private zu machen und einen public getter _getUnmodifiableHobbies_ zu implementieren, der mit _Collections.unmodifiableList_ eine unmodifiable List zurück gibt.

[EDIT]
Ups, Dein getter dürfte _getHobbys_ heißen. Im Englischen ist die Mehrzahl korrekterweise hobbies, deswegen hab ich's falsch gemacht.
[/EDIT]


----------



## Sanix (23. Apr 2012)

Kriegst du eine Exception beim Zugriff auf die Hobbies oder ist die Liste leer?

Duplicates kannst du versuchen mit 
	
	
	
	





```
select DISTINCT p from person p
```
 umgehen oder du verwendest ein Set für die Hobbies. Aber dein Problem scheint wo anders zu liegen.


----------



## damike (23. Apr 2012)

@nillehammer: das einfügen geht Problemlos. Die Daten sind meiner Meinung nach korrekt gesetzt:
Hobby hat eine Spalter PERSON_ID - die wird korrekt gesetzt

@Sanix: leere Liste. Sorry - da ich schon so viel probiert habe hab ich vergessen zu erwähnen dass

Exception Description: An attempt was made to traverse a relationship using indirection that had a null Session.  This often occurs when a n entity with an uninstantiated LAZY relationship is serialized and that lazy relationship is traversed after serialization.  To avoid this issue, ins tantiate the LAZY relationship prior to serialization.

fliegt. Aber warum LAZY wenn ich EAGER verwende?


----------



## nillehammer (23. Apr 2012)

> This often occurs when a n entity with an uninstantiated LAZY relationship is serialized and that lazy relationship is traversed after serialization.


Das hat mich noch auf eine Idee gebracht. Hobby implementiert bei Dir gar nicht Serializable. Einen Versuch wäre es wert...


----------



## damike (23. Apr 2012)

Hab ich schon versucht - bringt nichts. Hab auch schon EAGER auch bei Hobbies gemacht

Ich bin echt am Verzweifeln mit dem Teil :-S


----------



## EasyEagle (7. Mai 2012)

Also ich hab meine @ManyToOne Annotations immer so geschrieben:


```
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="PERSON_ID")  //also der Spaltenname der Personenspalte in der Hobbytabelle
private Person person;
```

Vielleicht hilfts


----------



## Tente (14. Mai 2012)

Hi,

um die Verknüpfungen musst du dich in deiner Anwendung schon selbst kümmern.
Du sagst zwar 
	
	
	
	





```
h1.setPerson(p);
```
, aber damit kennt das Hobby seine Person, aber die Liste der Hobbies in der Person muss ebenfalls geplegt werden! Also das Hobby manuell da über 
	
	
	
	





```
p.getHobbies.add(h1);
```
 einpflegen. JPA aktualisiert die Referenzen nicht bei jedem Zugriff auf das Objekt. Wenn es im Cache ist (was es nach dem persist ist), dann holt es auch genau erstmal dieses Objekt und aktualisiert es nicht mit zusätzlichen Informationen. Wären ja für JPA "sinnlose" selects. Referenzen müssen gegenseitig bekannt gemacht werden.


----------

