保存子数据时传递的要保持的分离实体

vuv7lop3  于 2022-10-30  发布在  Spring
关注(0)|答案(6)|浏览(140)

我在提交表单时收到此错误:
出现异常错误:传递到持久化的分离实体:项目模型账户;嵌套异常是javax.persistence。持久性异常:出现异常错误:传递到持久化的分离实体: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>

我做错了什么?

7rfyedvj

7rfyedvj1#

teamService.save(team);

保存方法只接受暂时对象。你可以找到什么暂时对象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对象,并尝试将其持久化到DB中,但该对象中包含Account对象,并且该Account对象已分离(意味着该对象的示例已保存到DB中,但该对象不在会话中)。Hibernate正在尝试保存它,因为您已指定:

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

因此,有几种方法可以修复它:
1)不要使用CascadeType.ALL配置。帐户对象可用于组数(至少域结构允许),并且更新操作可能会更新所有团队的帐户--这意味着此操作不应通过团队更新启动。我将从此处删除级联参数(默认值为无级联操作),如果您确实需要使用MERGE/DELETE配置。但如果您确实需要持久化它,请参阅选项#2
2)使用'saveOrUpdate()'方法而不是'save()'。'saveOrUpdate()'方法接受暂时的和分离的对象。但这种方法的问题在于设计:当你保存团队对象时,你真的需要插入/更新帐户吗?2我会把它分成两个操作,并防止从团队中更新帐户。
希望这对你有帮助。

ghhkc1vu

ghhkc1vu2#

由于设置了id而发生错误。Hibernate区分 transient 对象和分离对象,而Persistent仅适用于 transient 对象。

isteamService.save(team);

无法加载此操作中的ID,因为是@GeneratedValue

zour9fqk

zour9fqk3#

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

i5desfxk

i5desfxk4#

因为你的id是自动生成的值,所以不要从客户端发送它。我也遇到过同样的问题。请确保你没有为自动生成的属性提供值。

vcirk6k6

vcirk6k65#

当我尝试保存子实体,然后将新保存的实体作为参数传递给新的父对象时,发生了此错误。
例如:
ChildA a = childAService.save(childAObject);
Parent parent = new Parent() ;
parent.setChildA(a) // <=== Culprit
parentService.save(parent);
相反,请执行以下操作:
ChildA a = new ChildA();
parent.setChildA(a)
parentService.save(parent)
Hibernate会为您处理a的持久化,您不必自己去做。

oxiaedzo

oxiaedzo6#

要注意Lombok .toBuilder()方法--它正在创建对象的一个新示例,当您试图更新子对象的一部分时,这可能会引起相当大的误导。
示例:
第一个
这将在不显式调用www.example.com方法的情况下引发PersistentObjectExceptionuserRepo.save。
您需要执行以下操作:

var x = user.getX();
x.setA("New Value");

相关问题