Отдельная сущность передана для сохранения при сохранении дочерних данных

Я получаю эту ошибку при отправке формы:

org.hibernate.PersistentObjectException: отдельный объект передан в persist: com.project.pmet.model.Account; вложенное исключение - это javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: отдельная сущность, переданная в persist: com.project.pmet.model.Account

Вот мои сущности:

Аккаунт:

@Entity
@DynamicInsert
@DynamicUpdate
public class Account {

    @Id
    @GeneratedValue
    private Integer id;

    @Column(nullable = false)
    private String login;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    private String email;

    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
    private List<Team> ownedTeams;

    ...

Команда:

@Entity
@DynamicInsert
@DynamicUpdate
public class Team {

    @Id
    @GeneratedValue
    private Integer id;

    @Column(nullable = false)
    private String name;

    @ManyToOne
    @JoinColumn(name = "owner_id", nullable = false)
    private Account owner;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "team")
    private List<Account> members;

    ...

Вот часть контроллера:

    @ModelAttribute("team")
    public Team createTeamObject() {
        return new Team();
    }

    @RequestMapping(value = "/teams/create-team", method = RequestMethod.GET)
    public String getCreateTeam(@ModelAttribute("team") Team team, Principal principal) {
        logger.info("Welcome to the create team page!");

        Account owner = accountService.findOneByLogin(principal.getName());
        team.setOwner(owner);
        team.setMembers(new AutoPopulatingList<Account>(Account.class));

        return "teams";
    }

    @RequestMapping(value = "/teams/create-team", method = RequestMethod.POST)
    public String postCreateTeam(@ModelAttribute("team") Team team) {
        logger.info("Team created!");

        teamService.save(team);

        return "redirect:/teams.html";
    }

И форма:

<form:form commandName="team" id="teamForm">
      <div class="form-group">
          <label>Name</label>
          <form:input path="name" cssClass="form-control" />
      </div>
      <div class="form-group" id="row-template">
          <label>Members</label>
          <form:select path="members[0].id" cssClass="form-control" data-live-search="true" >
             <form:options items="${accounts}" itemValue="id" />
          </form:select>
          ...
      </div>
   <form:hidden path="owner.id" />
</form:form>

Что я делаю неправильно?


person keysersoze    schedule 27.12.2014    source источник


Ответы (4)


teamService.save(team);

Метод Save принимает только временные объекты. Что такое временный объект, вы можете найти здесь

Transient - an object is transient if it has just been instantiated using the new operator, and it is not associated with a Hibernate Session. It has no persistent representation in the database and no identifier value has been assigned. Transient instances will be destroyed by the garbage collector if the application does not hold a reference anymore. Use the Hibernate Session to make an object persistent (and let Hibernate take care of the SQL statements that need to be executed for this transition).

Вы получаете объект Team и пытаетесь сохранить его в БД, но в этом объекте есть объект Account, и этот объект Account отсоединен (означает, что экземпляр этого объекта сохранен в БД, но этот объект не находится в сеансе ). Hibernate пытается сохранить его, потому что вы указали:

@OneToMany(cascade = CascadeType.ALL, ....

Итак, есть несколько способов исправить это:

1) не используйте конфигурацию CascadeType.ALL. Объект учетной записи может использоваться для нескольких команд (по крайней мере, структура домена позволяет это), и операция обновления может обновить учетную запись для ВСЕХ команд - это означает, что эта операция не должна запускаться с обновлением команды. Я бы удалил оттуда параметр каскада (значение по умолчанию не каскадные операции), если вам действительно нужно использовать конфигурацию MERGE / DELETE. Но если вам действительно нужно сохранить это, посмотрите вариант №2.

2) используйте метод saveOrUpdate () вместо save (). Метод saveOrUpdate () принимает временные и отсоединенные объекты. Но проблема с этим подходом заключается в дизайне: вам действительно нужно вставлять / обновлять учетную запись при сохранении объекта Team? Я бы разделил его на две операции и запретил обновлять Аккаунт из Команды.

Надеюсь это поможет.

person Ilya Ovesnov    schedule 28.12.2014

Ошибка возникает из-за того, что установлен id. Hibernate различает временные и отсоединенные объекты, а persist работает только с временными объектами.

isteamService.save(team);

в этой операции не может быть загружен идентификатор, потому что это @GeneratedValue

person borchvm    schedule 28.12.2014
comment
Это идеальный ответ, убедитесь, что id не имеет значения. - person Michael Hegner; 18.09.2016
comment
О, значит, объекты с идентификатором, у которого есть @GeneratedValue, даже не могут быть сохранены, если этот идентификатор уже установлен? Я думал, что эта аннотация будет просто запасным вариантом. Приятно знать, что это не так! - person Froxx; 30.09.2017
comment
Убедитесь, что ваш id не установлен на 0, если ваш тип данных Integer, и это нормально, если тип данных id равен int. - person Ram; 21.10.2017
comment
Это был самый простой ответ, а также ключ для меня: у id была стратегия генерации, и я ее устанавливал! - person Carlos López Marí; 10.06.2021

Поскольку ваш идентификатор является автоматически сгенерированным значением, не отправляйте его со стороны клиента. У меня была такая же проблема. Убедитесь, что вы не указали значение для автоматически созданного атрибута.

person Pubudu    schedule 07.07.2017

Пожалуйста, измените @OneToMany (cascade = CascadeType.ALL, ..) на @OneToMany (cascade = CascadeType.REMOVE, ...) или другой, кроме CascadeType.PERSIST, и проблема решена.

person Nurmuhammad Tuhtasinov    schedule 11.02.2021