2010-04-15 6 views
8

Ich habe eine viele, Mai-Beziehung CohortGroup und Mitarbeiter. Jedes Mal, wenn ich einen Mitarbeiter in die CohortGroup-Gruppe einfüge, löscht der Hibernate die Gruppe aus der Auflösungstabelle und fügt alle Mitglieder sowie die neue Gruppe erneut ein. Warum nicht einfach das neue hinzufügen?Hibernate einfügen in eine Sammlung verursacht ein Löschen dann alle Elemente in der Sammlung wieder eingefügt werden

Die Anmerkung in der Gruppe:

@ManyToMany(cascade = { PERSIST, MERGE, REFRESH }) 
@JoinTable(name="MYSITE_RES_COHORT_GROUP_STAFF", 
joinColumns={@JoinColumn(name="COHORT_GROUPID")}, 
inverseJoinColumns={@JoinColumn(name="USERID")}) 
public List<Employee> getMembers(){ 
    return members; 
} 

Die andere Seite in der Employee

@ManyToMany(mappedBy="members",cascade = { PERSIST, MERGE, REFRESH }) 
public List<CohortGroup> getMemberGroups(){ 
    return memberGroups; 
} 

-Code

snipit
Employee emp = edao.findByID(cohortId); 
CohortGroup group = cgdao.findByID(Long.decode(groupId)); 
group.getMembers().add(emp); 
cgdao.persist(group); 

unten ist die SQL im Protokoll gemeldet

delete from swas.MYSITE_RES_COHORT_GROUP_STAFF where COHORT_GROUPID=? 
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) 
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) 
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) 
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) 
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) 
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) 

Dies scheint sehr ineffizient und verursacht einige Probleme. Wenn mehrere Anträge gestellt werden, um einen Mitarbeiter zur Gruppe hinzuzufügen, werden einige überschrieben.

Seams wie equals und hashCode könnten ein Grund dafür sein. Im Folgenden finden Sie die Implementierung für diese Methoden. Irgendwelche roten Fahnen?

CohortGroup

@Override 
public int hashCode() { 
    final int prime = 31; 
    int result = getName().hashCode(); 
    result = prime * result + ((emp == null) ? 0 : emp.hashCode()); 
    return result; 
} 
@Override 
public boolean equals(Object obj) { 
    if (this == obj) {return true;} 
    if (!(obj instanceof CohortGroup)) {return false;} 
    CohortGroup other = (CohortGroup) obj; 
    if(!getName().equals(other.getName())){return false;} 
    if (emp == null && other.getOwner() != null) { 
     return false; 
    } else if (!emp.equals(other.getOwner())) { 
     return false; 
    } 
    return true; 
} 

Mitarbeiter

 @Override 
public boolean equals(Object obj) { 
    if (this == obj) {return true;} 
    if (obj == null) {return false;} 
    if (!(obj instanceof Employee)) {return false;} 
    Employee other = (Employee) obj; 
    if (EMPLID == null && other.getEMPLID() != null) { 
     return false; 
    } else if (!EMPLID.equals(other.getEMPLID())) { 
     return false; 
    } 
    return true; 
} 

    @Override 
public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + ((EMPLID == null) ? 0 : EMPLID.hashCode()); 
    return result; 
} 

ich eine addMember Methode zum CohortGroup hinzugefügt haben, die zu beiden Seiten der Beziehung ergänzt:

public void addMember(Employee emp){ 
    this.getMembers().add(emp); 
    emp.getMemberGroups().add(this); 

} 

Fortsetzung Dank an alle, dass helfen.

+0

Ja, ich habe das gleiche Verhalten. Ich habe gerade gelernt, damit zu leben :-) Es passiert, wenn Sie eine Liste/Set auf einen Fremdschlüssel setzen –

+0

Also, was machst du damit zu leben? Verlangsamen Sie die Benutzeroberfläche, um dies zu verhindern. Ich habe eine Ajax-App, die diese Anfrage so schnell aufnehmen kann, wie der Benutzer klicken kann. Dies verursacht einige intermittierende Fehler an den Einsätzen. – Mark

+0

Ich hatte mehr oder weniger das gleiche Problem ... Habe Vertrauen! http://StackOverflow.com/Questions/179259 – Yuval

Antwort

0

Ich habe Einsätze wirken, um die Art, wie ich sie jetzt zu erwarten. Dank Pascal und z5h habe ich viel gelernt. Ich glaube, ich habe den HashCode und Equals korrekt implementiert. Das hat das Problem für mich nie gelöst. Stattdessen habe ich eine Intermediate Entity implementiert.

Für was es wert ist unten ist die Zuordnung in meiner Mitarbeiter, CohortGroup und jetzt CohortGroupMeember Klassen.

Mitarbeiter:

@OneToMany(mappedBy="member") 
public List<CohortGroupMember> getMemberGroups(){ 
    return memberGroups; 
} 
public void setMemberGroups(List<CohortGroupMember> grps){ 
    memberGroups = grps; 
} 

CohortGroupMember

@ManyToOne 
@JoinColumn(name="USERID") 
public Employee getMember(){ 
    return emp; 
} 
public void setMember(Employee e){ 
    emp = e; 
} 
@ManyToOne 
@JoinColumn(name="COHORT_GROUPID") 
public CohortGroup getGroup(){ 
    return group; 
} 
public void setGroup(CohortGroup cg){ 
    group = cg; 
} 

CohortGroup

@OneToMany(mappedBy="group") 
public List<CohortGroupMember> getMembers(){ 
    return members; 
} 
public void setMembers(List<CohortGroupMember> emps){ 
    members = emps; 
} 

Das Buch, das ich für diese gefolgt ist Java Persistence mit Hibernate Kapitel 7.2.3

+1

Obwohl dies eine Lösung ist. Die bessere Lösung besteht darin, ein Set anstelle einer Liste zu verwenden. Siehe den Artikel, den ich mit Marc's Antwort verlinkt habe. – JustinKSU

+0

@JustinKSU Danke Mann, ich schätze wirklich diesen tollen Artikel !!! Sie können immer etwas Neues über den Winterschlaf lernen :) –

0

Sie müssen hashCode() und equals() auf Ihren CohortGroup und Employee Einheiten definieren. Dies kann automatisch von Ihrer IDE vorgenommen werden und entweder auf dem Primärschlüssel (manchmal keine gute Idee) oder auf einem Geschäftsschlüssel (bevorzugt) erfolgen.

Gelesen this article.

+0

Danke für den Link zum Artikel, es hilft – Mark

7

Ich vermute sehr, dass Sie equals und hashCode nicht ordnungsgemäß überschreiben. Wenn Sie sie falsch überschreiben, kann dies zu einem Verhalten führen (da der Hash-Schlüssel in Karten als Schlüssel verwendet wird). Überprüfe, was du mit equals und hashCode gemacht hast.

Mit Ihre kommentierten Einheiten mit guten equals und hashCode, dieser Code (logisch äquivalent):

Session session = HibernateUtil.beginTransaction(); 
Employee emp = (Employee) session.load(Employee.class, 1L); 
CohortGroup group = (CohortGroup) session.load(CohortGroup.class, 1L); 
group.getMembers().add(emp); 
emp.getMemberGroup().add(group); // set the other side too!! 
session.saveOrUpdate(group); 
HibernateUtil.commitTransaction(); 

erzeugt die folgende Ausgabe auf meinem Rechner:

 
08:10:32.426 [main] DEBUG o.h.e.d.AbstractFlushingEventListener - processing flush-time cascades 
08:10:32.431 [main] DEBUG o.h.e.d.AbstractFlushingEventListener - dirty checking collections 
08:10:32.432 [main] DEBUG org.hibernate.engine.CollectionEntry - Collection dirty: [com.stackoverflow.q2649145.CohortGroup.members#1] 
08:10:32.432 [main] DEBUG org.hibernate.engine.CollectionEntry - Collection dirty: [com.stackoverflow.q2649145.Employee.memberGroup#1] 
08:10:32.443 [main] DEBUG org.hibernate.engine.Collections - Collection found: [com.stackoverflow.q2649145.CohortGroup.members#1], was: [com.stackoverflow.q2649145.CohortGroup.members#1] (initialized) 
08:10:32.448 [main] DEBUG org.hibernate.engine.Collections - Collection found: [com.stackoverflow.q2649145.Employee.memberGroup#1], was: [com.stackoverflow.q2649145.Employee.memberGroup#1] (uninitialized) 
08:10:32.460 [main] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 0 insertions, 0 updates, 0 deletions to 2 objects 
08:10:32.461 [main] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 0 (re)creations, 2 updates, 0 removals to 2 collections 
08:10:32.463 [main] DEBUG org.hibernate.pretty.Printer - listing entities: 
08:10:32.473 [main] DEBUG org.hibernate.pretty.Printer - com.stackoverflow.q2649145.CohortGroup{id=1, members=[com.stackoverflow.q2649145.Employee#1]} 
08:10:32.474 [main] DEBUG org.hibernate.pretty.Printer - com.stackoverflow.q2649145.Employee{id=1, memberGroup=} 
08:10:32.474 [main] DEBUG o.h.p.c.AbstractCollectionPersister - Inserting collection: [com.stackoverflow.q2649145.CohortGroup.members#1] 
08:10:32.480 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0) 
08:10:32.491 [main] DEBUG org.hibernate.SQL - insert into MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) 
Hibernate: insert into MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) 
08:10:32.496 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
08:10:32.497 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2 
08:10:32.499 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting collection: 1 rows inserted 

Nein vor dem Einfügen löschen !

By the way, beachten Sie, dass Sie den Link auf beiden Seiten setzen soll, wenn sie mit bidirektionalen Verbänden, wie ich auf die Gruppe auf den Mitarbeiter und tat.

oder defensive Link-Management-Methoden auf Klassen hinzufügen, zum Beispiel auf CohortGroup:

public void addToMembers(Employee emp) { 
    this.getMembers().add(emp); 
    emp.getMemberGroup().add(this); 
} 

public void removeFromMembers(Employee emp) { 
    this.getMembers().remove(emp); 
    emp.getMemberGroup().remove(this); 
} 
+0

Ich werde den Hash-Code und equals überprüfen. Sie sind implementiert, ich habe Eclipse nur für sie erstellt. Wenn das nicht der Trick ist, fange ich Ihre anderen Empfehlungen an. Ich werde meine Ergebnisse für Wohlstand veröffentlichen. – Mark

+0

Ich bin ziemlich sicher, dass ich den Hashcode und equals korrekt implementiert habe, aber das Verhalten bleibt. Wenn eine Gruppe zum ersten Mal hinzugefügt und ein Mitarbeiter hinzugefügt wird, gibt es kein Löschen. Es passiert einfach, wenn es bereits mehr als einen Mitarbeiter in der Gruppe gibt. Nicht sicher, ob Ihr Test einen Mitarbeiter zu einer Gruppe hinzugefügt hat, die bereits Mitarbeiter hat oder nicht. – Mark

+0

@Mark Ja, die Gruppe hatte 2 Mitarbeiter, wie in der Spur –

1

Wie andere vorgeschlagen haben, ist es wahrscheinlich ein Problem mit hashcode oder equals.

Konkret: Hibernate-Proxies verursachen Probleme mit instaceof, die Sie in Ihrer equals-Methode verwenden. Das buchstabiert schlechte Nachrichten.

Check this out: http://community.jboss.org/wiki/ProxyVisitorPattern

+0

Würde die equals-Methode ändern, um einen Vergleich der Klasse getName (this.getClass(). GetName(). Equals (other.getClass(). GetName()) zu machen, um das Problem zu umgehen, oder Hinweise auf die Verwendung der Besuchermuster, um diese Listen zu erhalten? – Mark

+0

Keine Änderung der Methode wird nicht funktionieren. Weil die proxied Klassen lustige Namen haben. Eine Sache, die Sie tun können, ist eine Methode wie so hinzuzufügen 'public Class getThisClass() {return this.getClass(); } '. Wenn Sie' getClass' auf dem Proxy aufrufen, erhalten Sie die Klasse des Proxys. Wenn Sie 'getThisClass' aufrufen, delegiert es in Ihre" echte "Klasse. Eine Art Hack im Vergleich zu Besucher. – z5h

+0

Müsste ich nicht einige hinzufügen checking, um sicherzustellen, dass die Methode existiert, bevor sie aufgerufen wird Der Grund für die equals ist eine instanceof, um sicherzustellen, dass das übergebene Objekt sicher umgesetzt werden kann Ich verstehe also nicht, wie die getThisClass funktionieren würde, wenn sie von der equals-Methode oder vom Besucher aufgerufen wird Option ist immer noch die beste c andidate zu erkunden. – Mark

5

Ich hatte Das selbe Problem und mit etwas Versuch und Irrtum gefunden, dass die Löschungen nicht vorkamen, wenn ich ein Set anstelle einer Liste als meine Ansammlung benutzte. Irritierend, da ich JSF verwende und die UI-Komponenten nur über Listen iterieren. Aber da ist es.

+3

Dies ist die Wurzel des Problems. Lesen Sie http://assarconsulting.blogspot.com/2009/08/why-hibernate-does-delete-all-then-re.html für weitere Details. – JustinKSU

+0

-1 weil ich das gleiche Problem mit Sets erlebt habe. Ihre Antwort wird jedem helfen, der das Entity Set innerhalb einer Hibernate-Sitzung aufrecht erhält und sich somit auf die Java-Standardidentität (==) verlassen kann. Zwischen zwei Hibernate-Sitzungen zeigen die Sets jedoch dasselbe Problem wie die Listen. Das Problem läuft auf die korrekte Implementierung von equals und hashCode hinaus. –

Verwandte Themen