«отдельная сущность передана для сохранения ошибки» с кодом JPA / EJB - PullRequest
75 голосов
/ 14 марта 2010

Я пытаюсь запустить этот базовый код JPA / EJB:

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

Я получаю эту ошибку:

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

Есть идеи?

Я ищу в Интернете и нашел причину:

Это было вызвано тем, как вы создали объекты, т. Е. Если вы явно указали свойство ID. Устранено присвоение идентификатора.

Но я не понял, что мне придется изменить, чтобы заставить код работать?

Ответы [ 9 ]

123 голосов
/ 14 марта 2010

Ошибка возникает из-за того, что ID объекта установлен. Hibernate различает временные и отдельные объекты, а persist работает только с временными объектами. Если persist решит, что объект отсоединен (что произойдет из-за установленного идентификатора), он вернет ошибку «отсоединенный объект передан для сохранения». Вы можете найти более подробную информацию здесь и здесь .

Однако это применимо только к , если вы указали первичный ключ для автоматической генерации: если поле сконфигурировано так, чтобы всегда устанавливаться вручную, тогда ваш код работает.

50 голосов
/ 05 февраля 2011

ERD

Допустим, у вас есть две сущности Album и Photo. Альбом содержит много фотографий, поэтому отношения один ко многим.

Альбом класса

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

Фото класс

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

    String photoName;

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

}

Перед сохранением или слиянием необходимо установить ссылку на альбом на каждой фотографии.

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

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

Вот как прикрепить связанный объект до того, как вы сохраните или объединитесь.

22 голосов
/ 20 апреля 2011

удалить

user.setId(1);

, поскольку он автоматически генерируется в БД и продолжается с помощью команды persist.

12 голосов
/ 14 марта 2010

Я получил ответ, я использовал:

em.persist(user);

Я использовал слияние вместо постоянного:

em.merge(user);

Но не знаю, почему упорство не сработало. (

9 голосов
/ 24 августа 2012

, если вы используете для генерации стратегии id = GenerationType.AUTO в вашей сущности.

Заменяет user.setId (1) на user.setId (null), и проблема решена.

5 голосов
/ 16 июля 2012

Здесь .persist () только вставит запись. Если мы используем .merge () , она проверит, существует ли запись с текущим идентификатором, если она существует он будет обновлен, иначе он вставит новую запись.

5 голосов
/ 06 июля 2012

Я знаю, что это слишком поздно, и каждый из них получил ответ. Но еще немного добавить к этому: когда установлен GenerateType, для объекта persist () ожидается получение сгенерированного идентификатора.

Если для пользователя уже задано значение Id, hibernate рассматривает его как сохраненную запись и поэтому он обрабатывается как отдельный.

если идентификатор равен нулю - в этой ситуации исключение нулевого указателя возникает, когда тип имеет тип AUTO или IDENTITY и т. Д., Если идентификатор не генерируется из таблицы или последовательности и т. Д.

design: это происходит, когда таблица имеет свойство bean-компонента в качестве первичного ключа. GenerateType должен быть установлен только тогда, когда идентификатор генерируется автоматически. удалите это, и вставка должна работать с идентификатором, указанным пользователем. (плохой дизайн иметь свойство, сопоставленное с полем первичного ключа)

3 голосов
/ 28 февраля 2016

Если вы указали в своей базе данных идентификатор в качестве первичного ключа и автоинкремента, то эта строка кода неверна:

user.setId(1);

Попробуйте с этим:

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }
2 голосов
/ 11 марта 2011

У меня была эта проблема, и она была вызвана кешем второго уровня:

  1. Я сохранил сущность, используя спящий режим
  2. Затем я удалил строку, созданную из отдельного процесса, который не взаимодействовал с кешем второго уровня
  3. Я сохранил другую сущность с тем же идентификатором (значения моего идентификатора не генерируются автоматически)

Следовательно, поскольку кэш не был аннулирован, hibernate предположил, что он имеет дело с отдельным экземпляром того же объекта.

...