Błąd Hibernate: inny obiekt o tej samej wartości identyfikatora był już powiązany z sesją

Zasadniczo mam kilka obiektów w tej konfiguracji (prawdziwy model danych jest nieco bardziej złożony):

  • A ma wiele do wielu relacji z B. (B Ma inverse="true")
  • B ma związek many-to-one z C. (mam cascade ustawione na "save-update")
  • C jest rodzajem tabeli typu / kategorii.

Powinienem również wspomnieć, że klucze podstawowe są generowane przez bazę danych w save.

Z moimi danymi, czasami napotykam problemy, w których A ma zestaw różne obiekty B, a te obiekty B odnoszą się do tego samego obiektu C.

Kiedy wywołuję session.saveOrUpdate(myAObject), pojawia się błąd hibernate: "a different object with the same identifier value was already associated with the session: C". Wiem, że hibernate nie może wstawić/zaktualizować/usunąć tego samego obiektu dwa razy w tej samej sesji, ale czy jest jakiś sposób na obejście tego? Nie wydaje mi się, żeby to była taka niezwykła sytuacja.

Podczas moich badań nad tym problemem, widziałem ludzi sugerujących użycie session.merge(), ale kiedy to robię, wszelkie "sprzeczne" obiekty są wstawiane do bazy danych jako puste obiekty ze wszystkimi wartościami ustawionymi na null. Najwyraźniej nie tego chcemy.

[Edytuj] inną rzeczą, o której zapomniałem wspomnieć, jest to, że (ze względów architektonicznych poza moją kontrolą) każdy odczyt lub zapis musi być wykonany w osobnej sesji.

Author: John, 2013-04-27

15 answers

Najprawdopodobniej dlatego, że obiekty B nie odnoszą się do tej samej instancji obiektu Java C. Odnoszą się one do tego samego wiersza w bazie danych (tj. tego samego klucza głównego), ale są jego różnymi kopiami.

Więc dzieje się tak, że sesja Hibernate, która zarządza obiektami, będzie śledzić, który obiekt Java odpowiada wierszowi z tym samym kluczem głównym.

Jedną z opcji byłoby upewnienie się, że encje obiektów B, które odnoszą się do ten sam wiersz odnosi się do tej samej instancji obiektu C. alternatywnie wyłącz kaskadowanie dla tej zmiennej członkowskiej. W ten sposób, gdy B jest utrzymywane C nie jest. Będziesz musiał zapisać C ręcznie osobno. Jeśli C jest tabelą typu / kategorii, to prawdopodobnie ma to sens.

 67
Author: jbx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-26 23:57:03

Po prostu ustaw kaskadę do scalania, to powinno załatwić sprawę.

 16
Author: an0r23j,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-08 21:21:51

Musisz zrobić tylko jedną rzecz. Uruchom session_object.clear(), a następnie zapisz nowy obiekt. Spowoduje to wyczyszczenie sesji (zgodnie z odpowiednią nazwą) i usunięcie naruszającego duplikatu obiektu z sesji.

 6
Author: dsk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-05 20:47:16

Przenieś zadanie przypisania ID obiektu z Hibernate do bazy danych za pomocą:

<generator class="native"/>
To rozwiązało problem.
 5
Author: user2845946,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-24 17:26:20

Zgadzam się z @ Hemant kumar, dziękuję bardzo. według jego rozwiązania, rozwiązałem swój problem.

Na przykład:

@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();
    }
}
Osoba.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;
    }

}

Ten kod zawsze popełnia błąd w mojej aplikacji: A different object with the same identifier value was already associated with the session później dowiedziałem się, że Frog to autoincrease my primary key!

Moim rozwiązaniem jest dodanie tego kodu do klucza głównego:

@GeneratedValue(strategy = GenerationType.AUTO)
 4
Author: Ice Blue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-25 08:19:52

Jednym ze sposobów rozwiązania powyższego problemu będzie nadpisanie hashcode().
Również przepłukać sesję hibernate przed i po zapisaniu.

getHibernateTemplate().flush();

Jawne ustawienie odłączonego obiektu na null również pomaga.

 3
Author: Waqar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-18 13:44:56

Oznacza to, że próbujesz zapisać wiele wierszy w tabeli z odniesieniem do tego samego obiektu.

Sprawdź właściwość id klasy encji.

@Id
private Integer id;

Do

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private Integer id;
 3
Author: rex roy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-23 07:19:56

Właśnie natknąłem się na tę wiadomość, ale w kodzie c#. Nie wiem, czy jest to istotne (dokładnie ten sam komunikat o błędzie).

Debugowałem kod za pomocą punktów przerwania i rozszerzałem niektóre Kolekcje za pomocą prywatnych członków, podczas gdy debugger znajdował się w punkcie przerwania. Ponowne uruchomienie kodu bez przekopywania się przez struktury sprawiło, że komunikat o błędzie zniknął. Wygląda na to, że przeglądanie prywatnych, leniwych kolekcji sprawiło, że NHibernate ładuje rzeczy, które nie powinny być ładowane w tym czasu (bo byli w prywatnych członkach).

Sam kod jest zawinięty w dość skomplikowaną transakcję, która może aktualizować dużą liczbę rekordów i wiele zależności w ramach tej transakcji (proces importu).

Mam nadzieję, że wskazówka dla każdego, kto natknie się na problem.

 2
Author: Ales Potocnik Hahonina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-18 09:54:58

Znajdź" kaskadę " atrybutu w Hibernate i usuń go. Po ustawieniu" Kaskada " dostępne, będzie wywoływać inne operacje (zapisać, aktualizować i usuwać) na innych jednostek, które mają związek z klasami pokrewnymi. / Align = "left" / U mnie zadziałało.

 2
Author: Nguyen Vu Quang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 13:51:49

Dodaj adnotację @ GeneratedValue do fasoli, którą wkładasz.

 1
Author: Hemant kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-26 12:01:49

Miałem ten błąd kilka dni i przyspieszyłem zbyt wiele czasu na naprawienie tego błędu.

 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;
    }
}

Zanim otrzymam ten błąd, nie wspomniałem o typie generowania ID w obiekcie OrderDetil. gdy nie generuje ID Orderdetails, zachowuje Id jako 0 dla każdego obiektu OrderDetail. to co # jbx wyjaśnił. Tak, to najlepsza odpowiedź. ten jeden przykład, jak to się dzieje.

 1
Author: Buddhi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-27 18:45:19

Spróbuj umieścić kod zapytania przed. To rozwiązuje mój problem. np. zmień to:

query1 
query2 - get the error 
update

Do tego:

query2
query1
update
 1
Author: user3738027,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-10 07:40:49

Możesz nie ustawiać identyfikatora obiektu przed wywołaniem zapytania update.

 0
Author: Fawad Khaliq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-11 09:59:42

Spotkałem się z problemem, ponieważ Generowanie klucza podstawowego jest złe, gdy wstawiam wiersz taki jak ten:

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());
        }
}

Zmieniam klasę generatora id na identity

<id name="id" type="int">
    <column name="id" />
    <generator class="identity"  />
 </id>
 0
Author: 张云风,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 06:41:01

W moim przypadku only flush() nie zadziałało. Musiałem użyć clear () po flush ().

public Object merge(final Object detachedInstance)
    {
        this.getHibernateTemplate().flush();
        this.getHibernateTemplate().clear();
        try
        {
            this.getHibernateTemplate().evict(detachedInstance);
        }
}
 0
Author: shubhranshu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-19 13:00:21