it-swarm.com.de

Ruhezustand: Ein anderes Objekt mit demselben Bezeichnerwert wurde bereits mit der Sitzung verknüpft

Ich habe im Wesentlichen einige Objekte in dieser Konfiguration (das reale Datenmodell ist etwas komplexer):

  • A hat eine Viele-zu-Viele-Beziehung zu B. (B hat inverse="true")
  • B hat eine Viele-zu-Eins-Beziehung zu C. (Ich habe cascade auf "save-update" gesetzt)
  • C ist eine Art Typ-/Kategorietabelle.

Außerdem sollte ich wahrscheinlich erwähnen, dass die Primärschlüssel beim Speichern von der Datenbank generiert werden.

Bei meinen Daten habe ich manchmal Probleme, bei denen A verschiedene B-Objekte hat und diese B-Objekte auf dasselbe C-Objekt verweisen.

Wenn ich session.saveOrUpdate(myAObject) anrufe, erhalte ich einen Fehler im Ruhezustand, der Folgendes angibt: "a different object with the same identifier value was already associated with the session: C". Ich weiß, dass der Ruhezustand das gleiche Objekt nicht zweimal in derselben Sitzung einfügen/aktualisieren/löschen kann, aber gibt es einen Ausweg? Dies scheint nicht so ungewöhnlich zu sein.

Während meiner Erforschung dieses Problems habe ich gesehen, dass Leute die Verwendung von session.merge() vorschlagen, aber wenn ich das tue, werden alle "widersprüchlichen" Objekte als leere Objekte in die Datenbank eingefügt, wobei alle Werte auf null gesetzt sind. Natürlich wollen wir das nicht.

[Bearbeiten] Eine andere Sache, die ich vergessen habe zu erwähnen, ist (aus architektonischen Gründen außerhalb meiner Kontrolle), dass jedes Lesen oder Schreiben in einer separaten Sitzung erfolgen muss.

64
John

Dies liegt höchstwahrscheinlich daran, dass die B-Objekte nicht auf dieselbe Java C-Objektinstanz verweisen. Sie beziehen sich auf dieselbe Zeile in der Datenbank (d. H. Auf denselben Primärschlüssel), sind jedoch unterschiedliche Kopien davon. 

Was passiert also ist, dass die Hibernate-Sitzung, die die Entitäten verwaltet, nachverfolgt, welches Java-Objekt der Zeile mit demselben Primärschlüssel entspricht.

Eine Möglichkeit wäre, sicherzustellen, dass die Entitäten von Objekten B, die sich auf dieselbe Zeile beziehen, sich tatsächlich auf dieselbe Objektinstanz von C beziehen. Auf diese Weise, wenn B persistiert, ist C nicht. Sie müssen C jedoch manuell separat speichern. Wenn C eine Typ-/Kategorietabelle ist, ist es wahrscheinlich sinnvoll, so zu sein.

71
jbx

Setzen Sie einfach Kaskade auf MERGE, das sollte den Trick tun.

18
4n0r23j

Sie müssen nur eine Sache tun. Führen Sie session_object.clear() aus und speichern Sie das neue Objekt. Dies löscht die Sitzung (entsprechend benannt) und entfernt das anstößige doppelte Objekt aus Ihrer Sitzung.

7
dsk

Übertragen Sie die Aufgabe zum Zuweisen der Objekt-ID aus Hibernate in die Datenbank, indem Sie Folgendes verwenden:

<generator class="native"/>

Dies hat das Problem für mich gelöst.

5
user2845946

Ich stimme mit @Hemant kumar überein, danke vielmals. Nach seiner Lösung habe ich mein Problem gelöst.

Zum Beispiel:

@Test
public void testSavePerson() {
    try (Session session = sessionFactory.openSession()) {
        Transaction tx = session.beginTransaction();
        Person person1 = new Person();
        Person person2 = new Person();
        person1.setName("222");
        person2.setName("111");
        session.save(person1);
        session.save(person2);
        tx.commit();
    }
}

Person.Java

public class Person {
    private int id;
    private String name;

    @Id
    @Column(name = "id")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Basic
    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Dieser Code macht immer Fehler in meiner Anwendung: A different object with the same identifier value was already associated with the session, Später habe ich herausgefunden, dass ich frogotto meinen Primärschlüssel autoincrease!  

meine Lösung ist, diesen Code auf Ihrem Primärschlüssel hinzuzufügen:

@GeneratedValue(strategy = GenerationType.AUTO)
4
Ice Blue

Eine Möglichkeit, das obige Problem zu lösen, besteht darin, die hashcode() zu überschreiben.
Auch die Hibernat-Sitzung vor und nach dem Speichern leeren. 

getHibernateTemplate().flush();

Das explizite Setzen des freistehenden Objekts auf null hilft auch.

3
Waqar

Dies bedeutet, dass Sie versuchen, mehrere Zeilen in Ihrer Tabelle mit dem Verweis auf dasselbe Objekt zu speichern.

Überprüfen Sie die ID-Eigenschaft Ihrer Entitätsklasse.

@Id
private Integer id;

zu

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private Integer id;
3
rex roy

Finden Sie das "Cascade" -Attribut in Hibernate und löschen Sie es. Wenn Sie "Cascade" als verfügbar festlegen, werden andere Vorgänge (Speichern, Aktualisieren und Löschen) für andere Entitäten aufgerufen, die eine Beziehung zu verwandten Klassen haben. So wird der gleiche Identitätswert geschehen. Es hat bei mir funktioniert.

2
Nguyen Vu Quang

Ich bin gerade auf diese Nachricht gestoßen aber in c # code Nicht sicher, ob es relevant ist (genau dieselbe Fehlermeldung).

Ich debugierte den Code mit Haltepunkten und erweiterte einige Sammlungen durch private Mitglieder, während der Debugger an einem Haltepunkt war. Nachdem Sie den Code erneut ausgeführt haben, ohne nach Strukturen zu suchen, wird die Fehlermeldung nicht mehr angezeigt. Es hat den Anschein, als hätte NHibernate Sachen, die zu diesem Zeitpunkt nicht geladen werden sollten (weil sie sich in privaten Mitgliedern befanden), dazu gezwungen war, in private, faul geladene Sammlungen zu blicken.

Der Code selbst ist in eine ziemlich komplizierte Transaktion eingebunden, die im Rahmen dieser Transaktion eine große Anzahl von Datensätzen und viele Abhängigkeiten aktualisieren kann (Importvorgang).

Hoffentlich ein Hinweis auf alle anderen, die auf das Problem stoßen.

Fügen Sie der Anmerkung, die Sie einfügen, die Anmerkung @ GeneratedValue hinzu.

2
Hemant kumar

Ich hatte diesen Fehler einige Tage entfernt und ich habe zu viel Zeit damit verbracht, diesen Fehler zu beheben. 

 public boolean save(OrderHeader header) {
    Session session = sessionFactory.openSession();


    Transaction transaction = session.beginTransaction();

    try {
        session.save(header);

        for (OrderDetail detail : header.getDetails()) {
            session.save(detail);
        }

        transaction.commit();
        session.close();

        return true;
    } catch (HibernateException exception) {

        exception.printStackTrace();
        transaction.rollback();
        return false;
    }
}

Bevor ich diesen Fehler bekomme, habe ich den ID-Generierungstyp im OrderDetil-Objekt nicht erwähnt. Wenn die ID der Bestelldetails nicht generiert wird, bleibt die ID für jedes OrderDetail-Objekt gleich 0. das, was #jbx erklärt hat. Ja, das ist die beste Antwort. Dieses ein Beispiel wie es passiert. 

1
Buddhi

Versuchen Sie, den Code Ihrer Abfrage vor ... zu platzieren. Dadurch wird mein Problem behoben. ändere das:

query1 
query2 - get the error 
update

zu diesem:

query2
query1
update
1
user3738027

wenn Sie EntityRepository verwenden, verwenden Sie saveAndFlush anstelle von save

0

Wenn in meinem IDE eine Registerkarte für Ausdrücke geöffnet bleibt, die einen Ruhezustand herbeiführt, wird das Objekt aufgerufen, das diese Ausnahme verursacht hat. Ich habe versucht, dasselbe Objekt zu löschen. Ich hatte auch einen Haltepunkt beim Delete-Aufruf, der notwendig zu sein scheint, damit dieser Fehler auftritt. Indem Sie einfach einen anderen Ausdrucks-Tab zum vorderen Tab machen oder die Einstellung so ändern, dass der ide nicht an Haltepunkten anhält, wurde dieses Problem behoben.

0
Aaron Byrnes

Ich bin auf das Problem gestoßen, weil der Primärschlüssel nicht korrekt erzeugt wird, wenn ich eine Zeile wie diese einfügen:

public void addTerminal(String typeOfDevice,Map<Byte,Integer> map) {
        // TODO Auto-generated method stub
        try {
            Set<Byte> keySet = map.keySet();
            for (Byte byte1 : keySet) {
                Device device=new Device();
                device.setNumDevice(DeviceCount.map.get(byte1));
                device.setTimestamp(System.currentTimeMillis());
                device.setTypeDevice(byte1);
                this.getHibernateTemplate().save(device);
            }
            System.out.println("hah");
        }catch (Exception e) {
            // TODO: handle exception
            logger.warn("wrong");
            logger.warn(e.getStackTrace()+e.getMessage());
        }
}

Ich ändere die ID-Generatorklasse in Identität

<id name="id" type="int">
    <column name="id" />
    <generator class="identity"  />
 </id>
0
张云风

In meinem Fall funktionierte nur Flush () nicht. Ich musste nach clear () ein clear () verwenden.

public Object merge(final Object detachedInstance)
    {
        this.getHibernateTemplate().flush();
        this.getHibernateTemplate().clear();
        try
        {
            this.getHibernateTemplate().evict(detachedInstance);
        }
}
0
shubhranshu

möglicherweise setzen Sie die ID des Objekts nicht vor dem Aufruf der Aktualisierungsabfrage.

0
Fawad Khaliq