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

标签 java spring hibernate cascade persistent

提交表单时出现此错误:

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 方法只接受 transient 对象。你能找到的 transient 对象是什么here

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

您正在获取 Team 对象并尝试将其持久保存到数据库中,但该对象中有 Account 对象并且该 Account 对象已分离(意味着该对象的实例已保存到数据库中但该对象没有在 session 中)。 Hibernate 正在尝试保存它,因为您已指定:

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

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

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

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

希望这会有所帮助。

关于java - 保存子数据时传递的分离实体持久化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27672337/

相关文章:

spring - 如何在 Spring Data JPA 中设置 Hibernate 命名策略

java - 无法在开放类次环境中启动 hazelcast。服务器套接字绑定(bind)失败。没有权限

java - JPA/Hibernate 只写字段,不读取

java - Hibernate(映射到交叉引用表)

java - 实现数字到字符串程序的替代且有效的方法是什么

java - OnBeforeSave 被调用但没有任何反应

java - Hibernate @Id @GenerateValue 注释无法识别 DB2 数据库生成的增量 ID

java - Java中的调用跟踪

java - Android JNI 从 Java 类中获取两个字段

java - Jackson API - 使用简单的动态对象反序列化 JSON