首页 > 解决方案 > 我们如何在 Hibernate (HBM) 中表示一个惰性多对一关系,同时允许在急切模式下引用同一个类?

问题描述

我正在尝试使我的休眠 HBM 文件中的一些多对一关系变得懒惰。具体来说,我有一个DataElement类,它以多对一的关系引用Filter元素,我想让它变得懒惰,同时在应用程序的其他部分保持对Filter的渴望。

我尝试更改我的 HBM 文件,发现lazy="true" 仅在类级别可用

DataElement的映射(我希望带有过滤器的多对一是惰性的

<hibernate-mapping package="project.me" default-lazy="false" auto-import="false">
  <class name="DataElement" table="DATA_ELEMENT">
    <id name="id" type="java.lang.Long" column="ID"/>
    <many-to-one name="filter" class="project.me.Filter" column="FILTER_ID" cascade="all"/>
  </class>
</hibernate-mapping>

FilterAudit的映射(我希望与过滤器的多对一是渴望的

<hibernate-mapping package="project.me" default-lazy="false" auto-import="false">
  <class name="FilterAudit" table="FILTER_AUDIT">
    <id name="id" type="java.lang.Long" column="ID"/>
    <many-to-one name="filter" class="project.me.Filter" column="FILTER_ID" cascade="all"/>
  </class>
</hibernate-mapping>

过滤器的映射

<hibernate-mapping package="project.me" default-lazy="false" auto-import="false">
    <class name="Filter" table="FILTERS" lazy="true">
        <id name="id" type="java.lang.Long" column="M_ID"/>
        <property name="type" type="filterType" column="M_FILTER_TYPE"/>
        <many-to-one name="predicate" class="Predicate" column="PRED_ID" unique="true" not-null="true" cascade="all"/>
    </class>
</hibernate-mapping>

通过将lazy="true" 放在Filter类的级别,我使应用程序中的所有DTO 都懒惰地加载Filter,我不希望这样

有没有办法只为DataElementFilter之间的关系指定延迟加载,同时保持FilterAuditFilter之间的负载渴望?

标签: javahibernatejpahbm

解决方案


我的建议:不要使用急切的获取。它会导致不一致,有时甚至是奇怪的查询。此外,使用 Eager fetching 时很难优化性能。在提到的情况下,我会创建不同的方法来使用一些获取连接或实体图来调用数据库。

我不使用 HBM(或其他基于 XML 的映射)。我使用注释为什么我不能为您提供 XML 映射的答案(无论如何 HBM 似乎已经过时了)。

我的首选方法是使用 JPA Criteria API 而不是 JPQL。有人说 JPQL 更容易理解,但我更喜欢类型安全的 Criteria API,它不易出错。我更喜欢实体图,因为它们比获取连接更易于动态使用。不过,其他选项也可以。

首先,我会根据Vlad Mihalcea 的文章设置实体类。(我推断出单向关系。)

@Entity
@Table(name = "DATA_ELEMENT")
public class DataElement {

    @Id
    @GeneratedValue
    @Column(name = "ID")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "FILTER_ID")
    private Filter filter;

    //Constructors, getters and setters...

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof DataElement )) return false;
        return id != null && id.equals(((DataElement) o).getId());
    }

    @Override
    public int hashCode() {
        return 56;
    }
}

FilterAudit(也)类似FetchType.LAZY...

然后Filter(没那么有趣,因为它是单向的)。

@Entity
@Table(name = "FILTERS")
public class Filter {

    @Id
    @GeneratedValue
    @Column(name = "M_ID")
    private Long id;

    // Other attributes omitted...

    //Constructors, getters and setters...

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Filter )) return false;
        return id != null && id.equals(((Filter) o).getId());
    }

    @Override
    public int hashCode() {
        return 14;
    }
}

现在,在这种情况下,使用 JPA Criteria API 和实体图实现了初始化延迟加载(或不初始化)的相关部分。

public DataElement findByIdWithFilter(long id) {

    EntityGraph<DatElement> graph = entityManager.createEntityGraph(DataElement.class);
    graph.addAttributeNodes("filter");

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<DatElement> cq = cb.createQuery(DatElement.class);
    Root<DatElement> root = cq.from(DatElement.class);

    cq.where(cb.equal(root.get("id"), id));

    TypedQuery<DatElement> typedQuery = entityManager.createQuery(cq);
    typedQuery.setHint("javax.persistence.fetchgraph", graph);

    DatElement response = null;
    try {
        response = typedQuery.getSingleResult();
    }
    catch(NoResultException nre) {}

    return response;
}

要检索没有关系的同一类的对象,只需省略实体图。

public DataElement findByIdWithoutFilter(long id) {

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<DatElement> cq = cb.createQuery(DatElement.class);
    Root<DatElement> root = cq.from(DatElement.class);

    cq.where(cb.equal(root.get("id"), id));

    return entityManager.createQuery(cq).getSingleResult();
}

推荐阅读