java – 保存子数据时传递给持久化的分离实体

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

org.hibernate.PersistentObjectException: detached entity passed to persist: com.project.pmet.model.Account; nested exception is javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to 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>

我究竟做错了什么?

解决方法:

teamService.save(team);

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

瞬态 – 如果一个对象刚刚使用new运算符进行实例化,并且它与Hibernate会话无关,则该对象是瞬态的.它在数据库中没有持久表示,并且没有分配标识符值.如果应用程序不再持有引用,则垃圾收集器将销毁瞬态实例.使用Hibernate Session使对象持久化(让Hibernate处理需要为此转换执行的SQL语句).

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

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

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

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

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

希望这可以帮助.

上一篇:php – 如何防止SQLITE SQLSTATE [HY000] [14]?


下一篇:PHP,MySQL和大量简单查询