保存子数据时传递的分离实体以保留

2022-09-01 23:59:47

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

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

    ...

以下是控制器的一部分:

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

我做错了什么?


答案 1
teamService.save(team);

保存方法仅接受瞬态对象。您可以在此处找到的瞬态对象是什么

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 对象已分离(意味着该对象的实例已保存到数据库中,但该对象不在会话中)。休眠正在尝试保存它,因为您已指定:

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

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

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

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

希望这有帮助。


答案 2

发生此错误的原因是设置了 id。休眠区分瞬态对象和分离对象,持久性仅适用于瞬态对象。

isteamService.save(team);

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


推荐