已分离的实体传递给持久性错误

时间:2014-12-27 23:14:20

标签: java spring hibernate cascade persistent

我在提交表单时收到此错误:

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;

    ...

这里是Controller的一部分:

    @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>

我做错了什么?

4 个答案:

答案 0 :(得分:29)

teamService.save(team);

Save方法仅接受瞬态对象。您可以找到什么是瞬态对象here

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对象并且您正在尝试将其持久保存到DB但该对象中包含Account对象并且该Account对象已分离(意味着该对象的实例已保存到DB中但该对象不是在会议中)。 Hibernate试图保存它,因为你已经指定了:

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

所以,有几种方法可以解决它:

1)不要使用CascadeType.ALL配置。帐户对象可用于多个团队(至少域结构允许),更新操作可能会更新所有团队的帐户 - 这意味着不应使用团队更新启动此操作。 我会从那里删除cascade参数(默认值是没有级联操作),如果你真的需要使用MERGE / DELETE配置。但如果你真的需要坚持下去,那么请看选项#2

2)使用'saveOrUpdate()'方法代替'save()'。 'saveOrUpdate()'方法接受瞬态和分离的对象。 但是这种方法的问题在于设计:在保存Team对象时是否真的需要插入/更新帐户?我会将其拆分为两个操作,并阻止从团队更新帐户。

希望这有帮助。

答案 1 :(得分:11)

发生错误是因为设置了 id 。 Hibernate区分瞬态和分离对象,而持久化仅适用于瞬态对象。

isteamService.save(team);

在此操作中无法加载id,因为是@GeneratedValue

答案 2 :(得分:3)

请将@OneToMany(cascade = CascadeType.ALL,..) 改为@OneToMany(cascade = CascadeType.REMOVE,...) 或除 CascadeType.PERSIST 之外的其他内容,问题已解决

答案 3 :(得分:0)

由于您的ID是自动生成的值,因此请勿从客户端发送。我有同样的问题。确保您没有为自动生成的属性提供值。