使用Hibernate 5,Spring 4
请考虑以下代码和两个实体之间的映射:
用户类
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private TruckOwner truckOwner;
//下面的getter setters
TruckOwner类
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
//下面的getter setter
当我的代码尝试更新内部的值时 user
类如下代码:
UserServiceImpl类
@Override
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void resetPassword(Long userId,String newPassword) {
User user = userDAO.findById(userId);
user.setPassword(newPassword);
System.out.println(user.getTruckOwner().getTruckOwnerId());
userDAO.merge(user);
}
打电话时 userDAO.merge(user);
我得到以下错误:
非瞬态实体具有空id:com.mymodel.TruckOwner
我在项目的很多地方遇到这种问题,请帮我解决这个问题,为什么TruckOwner类的所有内容都由hibernate设置为null?
我们应该知道的实施 userdao merge
方法,但我猜它被称为 merge
休眠的方法 Session
接口
在任何情况下,非瞬态对象都是 TruckOwner
目的;你打电话时,hibernat不会获取该对象 System.out.println(user.getTruckOwner().getTruckOwnerId());
此外,在那一点上你离开了休眠会话,如果你调用除了getTruckOwnerId()之外的任何其他getOwner getter你应该得到 org.hibernate.LazyInitializationException
(或类似..我不记得了)
我想你有两个选择:
- 根据staszko032的建议,您应该将获取类型更改为EAGER
- 使用时加载用户对象
userDAO.findById(userId);
你应该 fetch
通过调用其中的任何其他方法,在hibernate会话中的truckOwner对象 userDAO.findById(userId);
实现和hibernate会话内部
我希望它有用
安杰洛
试试卡车类:
@Entity
@Table(name = "truckOwner")
public class TruckOwner{
...
private User user;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "truckOwner", cascade = CascadeType.ALL)
public User getUser() {
return this.user;
}
}
这对于User类:
@Entity
@Table(name = "user")
public class User{
private TruckOwner truckOwner;
@OneToOne(fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
public TruckOwner getTruckOwner() {
return this.truckOwner ;
}
}
如果您正在制作生产应用程序,则渴望模式不是解决方案。当您尝试getTruckOwner时,您的会话中的问题已经关闭。尝试将会话传播给所有人 resetPassword
方法。
首先你不应该使用 merge
这里!你几乎不应该使用合并。
当您拥有非托管实体(由先前的持久化上下文序列化或加载)并希望将其合并到当前持久性上下文中时,应使用合并,以使其成为托管实体。由于您的DAO在容器管理的事务中加载了持久性上下文,因此您的实体已经被管理。这意味着您甚至不必调用save,在事务提交时将检测并保留对托管实体的任何更改。
从表面上看,JPA看起来很容易,因为很多复杂性在表面上看不到,当我7年前开始使用TopLink时,上帝知道我撞到了墙头,但在阅读之后 物体生命周期 和应用程序与容器管理的持久性上下文,我犯了更多的错误,并且更容易破译错误消息。
另一种解决方案是将用户类中的提取类型更改为EAGER模式。使用LAZY模式时,hibernate不会检索与用户连接的TruckOwner,因为在您的情况下并不明确需要它。最终,TruckOwner对于用户来说是空的,但是它设置了nullable = false选项,这就是合并失败的原因。