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

key*_*oze 15 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;

    ...
Run Code Online (Sandbox Code Playgroud)

球队:

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

    ...
Run Code Online (Sandbox Code Playgroud)

这是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";
    }
Run Code Online (Sandbox Code Playgroud)

形式:

<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>
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Ily*_*nov 37

teamService.save(team);
Run Code Online (Sandbox Code Playgroud)

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

@OneToMany(cascade = CascadeType.ALL, ....
Run Code Online (Sandbox Code Playgroud)

那么,你可以用几种方法来修复它:

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

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

希望这可以帮助.


bor*_*hvm 13

发生错误是因为已设置id.Hibernate区分瞬态和分离对象,并且持久化仅适用于瞬态对象.

isteamService.save(team);
Run Code Online (Sandbox Code Playgroud)

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

  • 哦,那么如果已经设置了 id 的对象,它甚至不能保存带有 `@GeneratedValue` 的 id 吗?我认为注释只是某种后备。很高兴知道它不是! (2认同)

小智 6

请更改@OneToMany(cascade = CascadeType.ALL,..)@OneToMany(cascade = CascadeType.REMOVE,...)或其他 except CascadeType.PERSIST,问题已解决


小智 5

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