[ Hibernate ] ManyToMany

Status
Nicht offen für weitere Antworten.

byte

Top Contributor
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:

Code:
   @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:

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


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

Code:
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
 
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
Code:
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.
Code:
SELECT d
  FROM DiaryEntry d
       LEFT JOIN FETCH d.persons
bzw. wenn es ein Inner-Join sein soll
Code:
SELECT d
  FROM DiaryEntry d
       JOIN FETCH d.persons
 
Das da sollte auch ein Outer-Join machen.
Code:
List<DiaryEntry> result = session.createCriteria(DiaryEntry.class)
                                 .setFetchMode("persons", FetchMode.JOIN)
                                 .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
                                 .list();
 
Leider kann ich hier nicht aufs Eager verzichten. Es funktioniert nun aber. Vielen dank.
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben