„Odłączona jednostka przekazana w celu utrwalenia błędu” z kodem JPA / EJB


81

Próbuję uruchomić ten podstawowy kod JPA / EJB:

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setId(1);
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }

Otrzymuję ten błąd:

javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.JPA.Database

Jakieś pomysły?

Wyszukuję w internecie i znalazłem powód:

Było to spowodowane sposobem tworzenia obiektów, tj. Jawnym ustawieniem właściwości ID. Usunięcie przypisania ID naprawiło to.

Ale nie rozumiem, co będę musiał zmodyfikować, aby kod działał?

Odpowiedzi:


50

ERD

Powiedzmy, że masz dwie jednostki Albumi Photo. Album zawiera wiele zdjęć, więc jest to relacja jeden do wielu.

Klasa albumu

@Entity
public class Album {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Integer albumId;

    String albumName;

    @OneToMany(targetEntity=Photo.class,mappedBy="album",cascade={CascadeType.ALL},orphanRemoval=true)
    Set<Photo> photos = new HashSet<Photo>();
}

Klasa fotograficzna

@Entity
public class Photo{
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Integer photo_id;

    String photoName;

    @ManyToOne(targetEntity=Album.class)
    @JoinColumn(name="album_id")
    Album album;

}

Przed utrwaleniem lub scaleniem należy ustawić odniesienie do albumu na każdym zdjęciu.

        Album myAlbum = new Album();
        Photo photo1 = new Photo();
        Photo photo2 = new Photo();

        photo1.setAlbum(myAlbum);
        photo2.setAlbum(myAlbum);       

W ten sposób należy dołączyć powiązaną jednostkę przed utrwaleniem lub scaleniem.


2
Jeśli używasz leków ogólnych, nie ma potrzeby używania „targetEntity = Photo.class”
Rollerball

cześć, po ustawieniu obiektu albumu na foto1 i foto2 ... jaki obiekt mamy zapisać listę zdjęć lub albumu?
Dilanka Rathnayake

130

Błąd występuje, ponieważ ustawiono identyfikator obiektu. Hibernate rozróżnia obiekty przejściowe i odłączone i persistdziała tylko z obiektami przejściowymi. Jeśli persistdojdzie do wniosku, że obiekt jest odłączony (co zrobi, ponieważ identyfikator jest ustawiony), zwróci błąd „odłączony obiekt przekazany do utrwalenia”. Więcej szczegółów znajdziesz tutaj i tutaj .

Ma to jednak zastosowanie tylko wtedy , gdy określono, że klucz podstawowy ma być generowany automatycznie: jeśli pole jest skonfigurowane tak, aby zawsze było ustawiane ręcznie, kod działa.


Czy technicznie będę miał rację, gdy powiem, że używam JPA, a nie Hibernacji, więc powyższe stwierdzenie nie powinno mieć zastosowania? Jestem nowicjuszem w JPA (dokładnie 3
ays

JPA Javadoc firmy Sun ( java.sun.com/javaee/5/docs/api/javax/persistence/ ) i Toplink są dokładnie takie same i sugerują, że masz rację techniczną. Jednak tak naprawdę sprowadza się to do tego, co specyfikacja mówi, że persist () powinno się zachowywać i niestety, nie wiem, co to jest.
Tomislav Nakic-Alfirevic

To rozwiązanie zadziałało dla mnie. Utrwalałem obiekt, przechowując gdzieś identyfikator. Następnie chcę nadpisać ten istniejący obiekt nową wartością, więc utworzyłem obiekt, skopiowałem identyfikator z powrotem i wybuchł, gdy próbowałem zapisać. W końcu musiałem ponownie sprawdzić bazę danych (findById), wprowadzić zmiany, a następnie utrwalić ten obiekt.
cs94njw

24

usunąć

user.setId(1);

ponieważ jest generowany automatycznie w bazie danych i kontynuuj z poleceniem persist.


12

Otrzymałem odpowiedź, użyłem:

em.persist(user);

Użyłem scalania zamiast trwałego:

em.merge(user);

Ale nie mam pojęcia, dlaczego upór nie zadziałał. :(


11
to nie jest rozwiązanie!
Ammar Bozorgvar

1
wiem, ale to zadziałało dla mnie. jakaś inna odpowiedź, która zadziałała dla Ciebie? jeśli tak, to z przyjemnością go wybiorę.
zengr

4
Zadziałało, ponieważ obiekt został odłączony od sesji hibernacji lub obiekt jest przejściowy, ale hibernacja postrzega go jako odłączony, ponieważ masz zadeklarowany klucz podstawowy.Za pomocą funkcji łączenia ponownie dołączasz obiekt do sesji, co umożliwia aktualizację obiektów w bazie danych ; patrz: docs.jboss.org/hibernate/core/3.3/reference/en/html/…
Ben

11

jeśli używasz do generowania id = GenerationType.AUTOstrategii w swojej jednostce.

Zastępuje user.setId (1)przez user.setId (null)i problem został rozwiązany.


5

Wiem, że jest za późno i każdy z nich dostał odpowiedź. Ale trochę więcej do dodania do tego: gdy jest ustawiona opcja GenerateType, oczekuje się, że persist () na obiekcie otrzyma wygenerowany identyfikator.

Jeśli istnieje już ustawiona wartość identyfikatora przez użytkownika, hibernacja traktuje go jako zapisany rekord, a więc jest traktowany jako odłączony.

jeśli id ​​jest null - w tej sytuacji wyjątek wskaźnika zerowego jest zgłaszany, gdy typ to AUTO lub IDENTITY itp., chyba że identyfikator jest generowany z tabeli lub sekwencji itp.

design: dzieje się tak, gdy tabela ma właściwość bean jako klucz podstawowy. GenerateType należy ustawić tylko wtedy, gdy identyfikator jest generowany automatycznie. usuń to, a insert powinien działać z identyfikatorem określonym przez użytkownika. (to zły projekt mieć właściwość mapowaną na pole klucza podstawowego)


5

Tutaj tylko .persist () wstawi rekord. Jeśli użyjemy .merge () , sprawdzi, czy istnieje jakiś rekord z bieżącym identyfikatorem, jeśli istnieje, zaktualizuje się, w przeciwnym razie wstawi nowy rekord.


Kosztowało mnie to mnóstwo czasu, zanim otrzymałem twoją odpowiedź. Dziękuję Ci bardzo!
Thach Van

3

Jeśli ustawisz id w swojej bazie danych jako klucz podstawowy i autoincrement, to ten wiersz kodu jest nieprawidłowy:

user.setId(1);

Spróbuj z tym:

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }

Próbowałem tego i wiem, że otrzymuję ten błąd:detached entity passed to persist
s1ddok

2

Miałem ten problem i był on spowodowany pamięcią podręczną drugiego poziomu:

  1. Utrwalałem byt używając hibernacji
  2. Następnie usunąłem wiersz utworzony z oddzielnego procesu, który nie współpracował z pamięcią podręczną drugiego poziomu
  3. Utrwaliłem inny podmiot z tym samym identyfikatorem (wartości moich identyfikatorów nie są generowane automatycznie)

Dlatego, ponieważ pamięć podręczna nie została unieważniona, hibernacja zakłada, że ​​ma do czynienia z odłączoną instancją tej samej jednostki.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.