Java 保存子数据时传递给持久化的分离实体
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27672337/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detached entity passed to persist when save the child data
提问by keysersoze
I'm getting this error when submitting the form:
提交表单时出现此错误:
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
org.hibernate.PersistentObjectException:分离的实体传递给持久化:com.project.pmet.model.Account;嵌套异常是 javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: 分离实体传递给持久性:com.project.pmet.model.Account
Here are my entities:
这是我的实体:
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;
...
Team:
团队:
@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;
...
Here's a part of the 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";
}
And the form:
和形式:
<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>
What am I doing wrong?
我究竟做错了什么?
采纳答案by Ilya Ovesnov
teamService.save(team);
Save method accepts only transient objects. What is the transient object you can find here
Save 方法只接受瞬态对象。您可以在此处找到的瞬态对象是什么
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).
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).
You are getting the Team object and you are trying to persist it to the DB but that object has Account object in it and that Account object is detached (means that instance of that object has saved into the DB but that object is not in the session). Hibernate is trying to save it because of you have specified:
您正在获取 Team 对象并尝试将其持久化到数据库中,但该对象中有 Account 对象并且该 Account 对象已分离(意味着该对象的实例已保存到数据库中,但该对象不在会话中)。由于您已指定,Hibernate 正在尝试保存它:
@OneToMany(cascade = CascadeType.ALL, ....
So, there are few ways how you can fix it:
因此,有几种方法可以修复它:
1) do not use CascadeType.ALL configuration. Account object can be used for number of Teams (at least domain structure allows it) and update operation might update Account for ALL Teams -- it means that this operation should not be initiated with Team update. I would remove cascade parameter from there (default value is no cascade operations), of if you really need use MERGE/DELETE configuration. But if you really need to persist it then see option #2
1) 不要使用 CascadeType.ALL 配置。帐户对象可用于多个团队(至少域结构允许),更新操作可能会更新所有团队的帐户——这意味着不应通过团队更新启动此操作。我会从那里删除级联参数(默认值是没有级联操作),如果你真的需要使用 MERGE/DELETE 配置。但是如果你真的需要坚持下去,那么请看选项#2
2) use 'saveOrUpdate()' method instead of 'save()'. 'saveOrUpdate()' method accepts transient and detached objects. But the problem with this approach is in design: do you really need to insert/update account when you are saving Team object? I would split it in two operations and prevent updating Account from the Team.
2) 使用“saveOrUpdate()”方法而不是“save()”。'saveOrUpdate()' 方法接受瞬态和分离的对象。但是这种方法的问题在于设计:在保存 Team 对象时,您真的需要插入/更新帐户吗?我会将其拆分为两个操作,并防止从团队更新帐户。
Hope this helps.
希望这可以帮助。
回答by borchvm
The error occurs because the idis set. Hibernate distinguishes between transient and detached objects and persist works only with transient objects.
发生错误是因为设置了id。Hibernate 区分瞬态对象和分离对象,并且持久化仅适用于瞬态对象。
isteamService.save(team);
in this operation can not be loaded id because is @GeneratedValue
在此操作中无法加载 id 因为是 @GeneratedValue
回答by Pubudu
Since your id is auto generated value, don't send it from client side. I had a same issue. Make sure that you does't provide a value for auto generated attribute.
由于您的 id 是自动生成的值,因此不要从客户端发送它。我有同样的问题。确保您没有为自动生成的属性提供值。