【问题标题】:Hibernate OneToOne mapped entity sets all properties to nullHibernate OneToOne 映射实体将所有属性设置为 null
【发布时间】:2017-09-07 17:44:38
【问题描述】:

使用 Hibernate 5、Spring 4

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

用户类

@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 类的所有内容都被休眠设置为空?

【问题讨论】:

  • 尝试打印用户ID
  • 试过了。它打印预期的...用户对象没有问题。
  • 你使用什么 id 生成策略?
  • @Id @GeneratedValue(strategy = GenerationType.IDENTITY)这个
  • 那是完全无效的答案。您不能通过调用 userDAO.merge 来保存/合并 truckOwner 对象,userDAO 和 truckOwnerDAO 是分开的。用户和卡车实体完全不同,仅通过映射连接。

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


【解决方案1】:

我们应该知道userdao merge方法的实现,但我猜它被称为hibernateSession接口的merge方法 在任何情况下,非瞬态对象都是TruckOwner 对象;当您调用 System.out.println(user.getTruckOwner().getTruckOwnerId()); 时,hibernat 不会获取该对象,而且此时您已退出休眠会话,并且如果您调用除 getTruckOwnerId() 之外的任何其他 truckOwner 的 getter,您应该得到 org.hibernate.LazyInitializationException (或类似的......我没有记错了)

我猜你有两个选择:

  1. 按照 staszko032 的建议,您应该将获取类型更改为 EAGER
  2. 当您使用userDAO.findById(userId); 加载用户对象时,您应该通过在userDAO.findById(userId); 实现和休眠会话内部调用任何其他方法来fetch 休眠会话内部的 truckOwner 对象

希望有用

安杰洛

【讨论】:

    【解决方案2】:

    在卡车课上试试这个:

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

    【讨论】:

      【解决方案3】:

      如果您正在制作生产应用程序,Eager 模式不是解决方案。问题是当您尝试 getTruckOwner 时,您的会话已经关闭。尝试将会话传播到所有resetPassword 方法。

      【讨论】:

        【解决方案4】:

        首先你不应该在这里使用merge!您几乎不应该使用合并。

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

        表面上 JPA​​ 看起来很简单,因为表面上看不到很多复杂性,天知道我在 7 年前开始使用 TopLink 时撞到了墙上,但是在阅读了 Object life cycles 和应用程序之后与容器管理的持久性上下文相比,我犯了更多的错误,而且更容易破译错误消息。

        【讨论】:

          【解决方案5】:

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

          【讨论】:

          • 试过了。不工作..同样的错误来了..另外,如果我没记错的话,在执行System.out.println(user.getTruckOwner().getTruckOwnerId()); 行时,休眠应该/必须获取TruckOwner 对象。
          猜你喜欢
          • 1970-01-01
          • 2013-04-05
          • 1970-01-01
          • 2013-06-26
          • 2021-12-03
          相关资源
          最近更新 更多