Hibernate OneToOne映射实体将所有属性设置为null

时间:2017-04-12 05:42:34

标签: java spring hibernate mapping one-to-one

使用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设置的?

5 个答案:

答案 0 :(得分:3)

我们应该知道userdao merge方法的实现,但我想它被称为hibernate merge接口的Session方法 在任何情况下,非瞬态对象都是TruckOwner对象;当你打电话给System.out.println(user.getTruckOwner().getTruckOwnerId());时,hibernat将不会获取该对象。此时你已经离开了休眠会话,如果你调用除了getTruckOwnerId()之外的任何其他getOwner getter,你应该得到org.hibernate.LazyInitializationException(或类似的。我不记得了。

我猜你有两个选择:

  1. 根据staszko032的建议,您应该将获取类型更改为EAGER
  2. 当您使用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选项,这就是合并失败的原因。