【问题标题】:Detached entity passed to persist when save the child data保存子数据时传递的分离实体持久化
【发布时间】:2015-02-24 15:55:27
【问题描述】:

提交表单时出现此错误:

org.hibernate.PersistentObjectException:分离的实体传递给持久化:com.project.pmet.model.Account;嵌套异常是 javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: 分离实体传递给持久化: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>

我做错了什么?

【问题讨论】:

    标签: java spring hibernate cascade persistent


    【解决方案1】:
    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 对象并尝试将其持久保存到数据库中,但该对象中有 Account 对象并且该 Account 对象已分离(意味着该对象的实例已保存到数据库中但该对象没有在会话中)。 Hibernate 正在尝试保存它,因为您已指定:

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

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

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

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

    希望这会有所帮助。

    【讨论】:

    • @OneToMany(cascade = CascadeType.ALL, .... 为我工作。我也从你的解释中理解了原因;谢谢!
    【解决方案2】:

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

    isteamService.save(team);
    

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

    【讨论】:

    • 这是完美的答案,确保 id 没有价值。
    • 哦,如果该 id 已设置,那么 ID 为 @GeneratedValue 的对象甚至无法保存?我认为注释只是某种后备。很高兴知道它不是!
    • 如果你的数据类型是Integer,确保你的id没有设置为0,如果id数据类型是int也没关系。
    • 这是最简单的答案,也是我的关键:id 有一个生成策略,我正在设置它!
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2013-06-26
        • 2018-06-09
        • 1970-01-01
        • 2017-04-01
        • 2018-09-22
        • 1970-01-01
        • 2018-05-25
        • 2017-10-21
        • 1970-01-01
        相关资源
        最近更新 更多