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

11

使用Hibernate 5和Spring 4

请参考以下代码以及两个实体之间的映射:

User类

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private TruckOwner truckOwner;

//以下是getter和setter方法

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设置为所有内容为空?

尝试过了,它打印出了预期的结果...用户对象没有问题。 - user7041082
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) 这个。 - user7041082
@sumit,你能展示一下哪些实际的方法被标注了 @Transactional 吗? - Eugene
你能合并子类吗?尝试合并子对象。 - user5122076
1
这完全是无效的答案。 你不能通过调用userDAO.merge来保存/合并truckOwner对象。userDAO和truckOwnerDAO是分开的。 user和truck实体彼此完全不同,只是通过映射关联在一起。 - user7041082
显示剩余8条评论
5个回答

3

如果您正在开发生产应用程序,那么热切模式并不是一个解决方案。问题在于当您尝试获取TruckOwner时,您的会话已经关闭。请尝试将会话传播到所有resetPassword方法中。


3

首先,在这里你不应该使用 merge!你几乎永远不应该使用Merge。

Merge应该用于当您有一个未管理的实体(序列化或由先前的持久性上下文加载)并希望将其合并到当前的持久性上下文中以使其成为受管理的实体时使用。由于持久性上下文已经加载了包含DAO的事务,因此您的实体已经是受管理的。这意味着您甚至不必调用save,对受管实体的任何更改都将在事务提交时检测并持久化。

在表面上,JPA看起来很容易,因为很多复杂性在表面上是不可见的。当我7年前开始使用TopLink时,我曾经为此苦恼许多次。但是,阅读有关对象生命周期和应用程序与容器管理的持久性上下文的信息后,我犯了更多错误,并且更容易解密错误消息。


3
我们应该了解userdao merge方法的实现,但我猜这被称为hibernate Session接口的merge方法。无论如何,非瞬态对象是TruckOwner对象;当您调用System.out.println(user.getTruckOwner().getTruckOwnerId());时,Hibernate不会获取该对象,而且在那一点上,您已经退出了Hibernate会话,如果您调用除getTruckOwnerId()之外的任何其他getter方法,则应该得到org.hibernate.LazyInitializationException(或类似的异常..我记不清了)。
我猜你有两个选择:
1.像staszko032建议的那样,将获取类型更改为EAGER。 2.当您使用userDAO.findById(userId);加载用户对象时,您应该通过调用userDAO.findById(userId);实现内部的任何其他方法并在Hibernate会话中获取truckOwner对象。
希望对您有所帮助。
Angelo

3

对于 truck 类,尝试以下操作:

@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;
}
}

针对用户类的内容如下:

@Entity
@Table(name = "user")
public class User{
     private TruckOwner truckOwner;


    @OneToOne(fetch = FetchType.LAZY)
    @PrimaryKeyJoinColumn
     public TruckOwner getTruckOwner() {
          return this.truckOwner ;
     }

}

1
另一种解决方案是将User类的fetch类型更改为EAGER模式。使用LAZY模式,Hibernate不会检索与用户连接的TruckOwner,因为在您的情况下它并不明确需要。最终,对于用户来说,TruckOwner为空,但它具有nullable = false选项设置,这就是合并失败的原因。

1
尝试过了,不起作用..还是出现相同的错误..此外,在懒加载的情况下,当执行System.out.println(user.getTruckOwner().getTruckOwnerId());这一行时,Hibernate应该/必须获取TruckOwner对象,如果我没有记错的话。 - user7041082

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接