# [ Hibernate ] ManyToMany



## byte (15. Feb 2008)

Mahlzeit,

ich habe ein Problem mit einem Hibernate-Mapping. Erstmal zu meinem Modell: Objekte vom Typ DiaryEntry können 0..* Objekte vom Typ DiaryUser besitzen. In meiner Klasse DiaryEntry habe ich nun folgendes Mapping definiert:


```
@ManyToMany(cascade={CascadeType.REFRESH}, fetch=FetchType.EAGER)
    @JoinTable(
        name="EntryPersons",
        joinColumns={ @JoinColumn(name="entry_id") },
        inverseJoinColumns={ @JoinColumn(name="person_id") }
    )
    public Set<DiaryUser> getPersons() {
        return this.persons;
    }
```

Das DB-Schema wird korrekt erzeugt (Tabelle Entries und Persons sowie eine Assoziationstabelle EntryPersons mit Foreign Keys auf die jeweiligen Tabellen).

Das Problem ist nun folgendes: Ich habe testweise ein DiaryEntry angelegt, das drei DiaryUser hat. Wenn ich nun alle DiaryEntry Objekte mit Hilfe von HQL abrufe, bekomme ich korrekterweise das eine DiaryEntry Objekt zurück:


```
List<DiaryEntry> result = session.createQuery("from DiaryEntry").list();
```


Wenn ich jedoch stattdessen mit der Criteria-API arbeite, bekomme ich das gleiche DiaryEntry Objekt dreimal:


```
List<DiaryEntry> result = session.createCriteria(DiaryEntry.class).list();
```

Wenn ich entsprechend vorher zwei DiaryUser assoziere, dann liefert er auch entsprechend nur zwei DiaryEntry Objekte (jeweils mit identischem Inhalt).

Weiss jemand, woran das liegt? Habe entsprechende SQL angeguckt, unterscheidet sich ziemlich. Aber sollten die beiden Aufrufe (HQL, Criteria) nicht eigentlich zum gleichen Ergebnis führen? Stimmt irgendwas mit dem Mapping nicht oder muss ich das Criteria noch irgendwie anpassen?

Weiss nicht so richtig, wo ich ansetzen soll, weil es mit HQL ja funktioniert, ich aber gerne die Criteria-API nutzen will.

TIA byto


----------



## Guest (15. Feb 2008)

Das liegt an dem "fetch=FetchType.EAGER" für die Collection. Bei einer HQL Query hast du eigentlich auch drei Zeilen, die werden aber 
passend verpackt. Schau dir den generierten SQL-Code an und führe ihn aus.

Versuche das hier
	
	
	
	





```
List<DiaryEntry> result = session.createCriteria(DiaryEntry.class)
                                 .setResultTransformer(Criteria.ROOT_ENTITY)
                                 .list();
Set<DiaryEntry> distinctResult = new LinkedHashSet<DiaryEntry>(result);

oder

List<DiaryEntry> result = session.createCriteria(DiaryEntry.class)
                                 .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
                                 .list();
```
Ich würde dir empfehlen auf das EAGER-Loading bei Collections zu verzichten und stattdessen entsprechende NamedQueries
zu schreiben, für die Fälle, wo du wirklich alles brauchst. Das verringert die Datenmenge, die "durch die Leitung" muss.
z.B.
	
	
	
	





```
SELECT d
  FROM DiaryEntry d
       LEFT JOIN FETCH d.persons
```
bzw. wenn es ein Inner-Join sein soll
	
	
	
	





```
SELECT d
  FROM DiaryEntry d
       JOIN FETCH d.persons
```


----------



## Guest (15. Feb 2008)

Das da sollte auch ein Outer-Join machen.
	
	
	
	





```
List<DiaryEntry> result = session.createCriteria(DiaryEntry.class)
                                 .setFetchMode("persons", FetchMode.JOIN)
                                 .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
                                 .list();
```


----------



## byte (18. Feb 2008)

Leider kann ich hier nicht aufs Eager verzichten. Es funktioniert nun aber. Vielen dank.


----------

