使用 Session.buildLockRequest() 将实体重新附加到 EntityManager 是一个实用的解决方案吗?

Is the use of Session.buildLockRequest() to reattach entity to EntityManager a practical solution?

我的问题比较简单:

我有一个实体,其中包含许多我并不总是需要的延迟加载集。现在我不想急切地加载所有东西,也不想有几个不同的 getSlimEntity()、getFullEntity()、getEntityForSpecialOccasion() 方法。

我想做的是默认使用 'slim' 版本,然后按需加载惰性内容。该需求可能源于更改显示 'task' 实体的网页上的选项卡。新选项卡应显示任务的历史记录。不过这个选项卡用得不多,所以我不急着要数据。

解决方案应该尽可能少地在数据库上工作,因为数据库性能对我们来说是一个问题。

我想到的一个可能的解决方案是使用 Session.buildLockRequest() 将任务 're-attach' 交给 EntityManager 并在我需要的 Set 上调用 Hibernate.initialize() 。它看起来像这样:

public Set<HistoryEntry> getHistory(Task task) {

    Session session = manager.unwrap(Session.class);
    session.buildLockRequest(LockOptions.NONE).lock(task);

    Hibernate.initialize(task.getHistory());

    return task.getHistory();
}

这是一个简洁且相对容易理解的解决方案,而且数据库没有更新或任何东西,只是查询有问题的 HistoryEntries。

现在我的问题是:这个解决方案可以使用吗?它会带来任何我看不到的问题吗?调用 buildLockRequest 到底发生了什么?另外,多个用户查看同一个任务会不会有问题?

// 编辑:如前所述,此解决方案使用 Hibernate 特定调用,这些调用可能与其他 Persistence Provider(如 EclipseLink 或 OpenJPA)不兼容。由于此项目仅供内部使用,因此这应该不是问题。

我不确定使用 LockRequest#lock() 将对象重新附加到会话(顺便说一下,它 behaves strangely 因为它不进行任何版本检查或同步更改)是否是个好主意。在您的情况下,这似乎是一个合适的解决方案,但它看起来只是一种副作用,我不会依赖此功能。

另一件事是 - 正如 MWiesner 已经在评论中指出的那样,在使用 JPA 时谈论 Hibernate 特定调用是不好的。

你有很多选择:

  1. 如果您知道在从数据库检索时将如何使用对象 - 请使用 entity graphs
  2. 您可以只进行查询检索所有 Histories 传递的实体。
  3. 如果您知道传递的对象无法更改,您可以通过 EntityManager#merge.
  4. 将其重新附加到持久性上下文

为什么不 select 以上之一?