【问题标题】:Prevent Hibernate from loading lazy ManyToOne防止 Hibernate 加载懒惰的 ManyToOne
【发布时间】:2014-07-15 12:39:58
【问题描述】:

我将模型中的问题减少到 3 个实体:

  • 车站。
  • 位置(每个站点多个)。
  • 位置组(每个站点多个)。

Location 类:

@Entity
@Table(name = "***")
public class Location {

   @ManyToOne
   @JoinColumn(name = "s_id")
   private Station s;

   @ManyToOne
   @JoinColumn(name = "g_id")
   private GroupOfLocations group;      

 }

还有GroupOfLocation 的类:

@Entity
@Table(name = "***")
public class GroupOfLocation {

  @ManyToOne(fetch = FetchType.LAZY) //I do not want the Station to be loaded
  @JoinColumn(name = "s_id")
  private Station s;

}

当我通过 ID 获得位置时:

  1. 其站点已加载
  2. 位置组已加载
  3. 群组的站已加载我不需要它。

问题:该组包含该站,但我不希望它被加载。我预计 fetch = FetchType.LAZY 会阻止 Station 完全加载,但它不起作用。

我在 SO 上进行了搜索,有时,问题来自声明为 final 的类,但此模型中没有最终类。

有什么想法吗?

这是通过 ID 搜索实体 id 的方式:

public Location getById(Integer id) {
  CriteriaBuilder cb = em.getCriteriaBuilder();
  CriteriaQuery<Location> query = cb.createQuery(Location.class);
  Root<Location> entity = query.from(Location.class);
  Predicate whereClause = cb.equal(entity.get(Location_.id), id);
  query.where(whereClause); 
  return em.createQuery(query).getSingleResult();
}

【问题讨论】:

    标签: java hibernate jpa orm hibernate-mapping


    【解决方案1】:

    任何 JPQL 或 Criteria 查询都将转到 override the default 获取计划(您在实体映射中定义的计划)。

    默认查询计划仅在使用 find 或 getReference 加载实体时有效

    entityManager.find(GroupOfLocation.class, 1L);
    

    默认的 @ManyToOne 提取是 EAGER,但由于您尚未发出连接提取,因此将通过一些额外的选择来提取这些提取。

    location.group.station 不会通过额外的选择来获取,但代理仍然存在。

    如果 location.station 恰好与 location.group.station 匹配,那么 Hibernate 将使用已经加载的 location.station,因为在 Hibernate Session 对象内部相等匹配实例也相等(意味着只能有一个具有给定实体标识符的 Entity 类型的对象)。

    因此,如果 location.group.stationlocation.station 引用相同的实体,您将看到已初始化的代理,否则代理将保持未初始化状态。

    如果会话已关闭且代理未初始化,您将在访问它时收到延迟异常。

    【讨论】:

    • 非常完整和有趣的答案。我尝试使用/不使用em.find() 并使用相同/不同的站 ID(即 location.station.id != location.group.station.id)。当 station.id 不同时,永远不会加载 location.group.station(似乎在这两种情况下都尊重 FetchType。)。我尝试查看使用 em.find 是否制定了 2 个不同的获取计划。你知道是否有办法告诉hibernate为第二站显式设置null? (我将模型转换为 JSON 格式,这使得该站被复制。)
    • 在数据库中存在实际关联行的情况下,无法强制为 null。我将加载实体并创建一个替代 DTO 结构,它将成为您的 JSON 模型。这样,您也可以将 JPA 模型与 JSON 视图模型分开。它既干净又可以轻松处理循环依赖,即使您必须做更多工作才能完成此任务。
    • 那么实际的答案是什么...?
    【解决方案2】:

    但是您没有在位置的 s & group 属性上声明 fetch = FetchType.LAZY。

    【讨论】:

    • 我不明白你的意思。我没有声明fetch = FetchType.LAZYon 位置的组属性,因为我需要获取组。但是,我不想获取该组的电台。
    • 弗拉德刚刚给出了答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 2016-10-07
    • 2014-03-03
    • 1970-01-01
    • 2011-07-09
    相关资源
    最近更新 更多