Spring 数据,JPA @ManyToOne 延迟初始化不工作

Spring Data, JPA @ManyToOne lazy initialization not working

我知道有很多关于这个问题的类似问题,但对我没有任何帮助。

我在 Aim 和 User 之间有 @ManyToOne 关系。

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id", nullable = false, updatable = false)
private User user;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private Collection<Aim> userAims;

分别

@Override
@Transactional(propagation = Propagation.REQUIRED)
@PreAuthorize("isAuthenticated() and principal.user.isEnabled() == true")
public Aim findById(String aimId) throws NumberFormatException, EntityNotFoundException {
    Aim aim = null;
    try {
        aim = aimRepository.findOne(Long.parseLong(aimId));
    } catch (NumberFormatException e) {
        throw new InvalidDataAccessApiUsageException(e.getMessage(), e);
    }
    if (aim == null) throw new EntityNotFoundException("Aim with id: " + aimId + " not found!");
    return aim;
}

@OneToMany 关联在延迟抓取下工作良好。方法未嵌套到另一个 @Transactional 方法,因此 @Transactional 工作正常。




So the record exists.

  1. UserAim 不是 final 并实施 可序列化
  2. 一些消息来源建议在 getter 上添加注释。它也没有 工作。
  3. @Fetch(FetchMode.SELECT)同样的情况=\
  4. 通过 Hibernate 查询的结果相同,但使用 left join 的 HQL 查询 fetch 工作正常
  5. 我的 FK ON UPDATE CASCADE ON INSERT CASCADE
  6. optional = false也试过...

Pay attention that I haven't the LazyInitException



在此先感谢!

我从您的 findById 方法中的代码以及标题中对 "lazy initialization not working" 的引用中猜测,您想要找到一个 Aim object 通过它的数字 ID,以及关联的 User object.

为了使用 lazy-loading 执行此操作,您需要 'get' 关联的 object,并且(最重要的是)您需要 'get' 关联的其中一个实体的字段。

所以 try 块中的代码应该是:

aim = aimRepository.findOne(Long.parseLong(aimId));
if (aim != null && aim.getUser() != null) {
    aim.getUser().getUserId(); // doesn't need to be assigned to anything
}

或者,如果您有可用的记录器,您可以在调试或跟踪日志消息中使用 userId

if (aim != null && aim.getUser() != null) {
    logger.debug("Lazy-loaded User " + aim.getUser().getUserId());
}

这有一个额外的好处,您可以调试事情的进展情况 lazy-loaded。

顺便说一句,我们发现让查找例程在未找到某些东西时抛出异常是一个糟糕的主意。这是因为您可能想使用查找例程来查明实体是否 NOT 存在。如果这是在事务中发生的,您的异常可能会触发不需要的回滚(除非您特别忽略它)。最好 return null 并检查它而不是使用 try ... catch.