使用Hibernate 5,Spring 4
请考虑以下代码和两个实体之间的映射:
用户类
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private TruckOwner truckOwner;
//下面的getter setters
TruckOwner class
@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设置的?
答案 0 :(得分:3)
我们应该知道userdao merge
方法的实现,但我想它被称为hibernate merge
接口的Session
方法
在任何情况下,非瞬态对象都是TruckOwner
对象;当你打电话给System.out.println(user.getTruckOwner().getTruckOwnerId());
时,hibernat将不会获取该对象。此时你已经离开了休眠会话,如果你调用除了getTruckOwnerId()之外的任何其他getOwner getter,你应该得到org.hibernate.LazyInitializationException
(或类似的。我不记得了。
我猜你有两个选择:
userDAO.findById(userId);
加载用户对象时,您应该通过调用fetch
实现中的任何其他方法以及hibernate会话内的任何其他方法来userDAO.findById(userId);
hibernate会话中的truckOwner对象< / LI>
醇>
我希望它有用
安吉洛
答案 1 :(得分:3)
尝试使用卡车类:
@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 ;
}
}
答案 2 :(得分:3)
如果您正在制作生产应用程序,则急切模式不是解决方案。当您尝试getTruckOwner时,您的会话中的问题已经关闭。尝试将会话传播到所有resetPassword
方法。
答案 3 :(得分:3)
首先,你不应该在这里使用merge
!你几乎不应该使用合并。
当您拥有非托管实体(由先前的持久化上下文序列化或加载)并希望将其合并到当前持久性上下文中时,应使用合并,以使其成为托管实体。由于您的DAO在容器管理的事务中加载了持久性上下文,因此您的实体已经被管理。这意味着您甚至不必调用save,当事务提交时,将检测并保留对托管实体的任何更改。
从表面上看,JPA看起来很简单,因为很多复杂性在表面上看不到,上帝知道我在7年前开始使用TopLink时头撞墙,但在阅读了Object life cycles之后和应用程序与容器管理的持久性上下文,我犯了更多的错误,并且更容易破译错误消息。
答案 4 :(得分:1)
另一种解决方案是将用户类中的提取类型更改为EAGER模式。使用LAZY模式时,hibernate不会检索与用户连接的TruckOwner,因为在您的情况下并不明确需要它。最终,TruckOwner对用户来说是空的,但它设置了nullable = false选项,这就是合并失败的原因。