JPA Criteria API - 设置从已加入的实体加入和获取数据

时间:2015-05-11 21:39:01

标签: java hibernate jpa criteria criteria-api

我有两个实体FooFooDerivedData,如下所述。

实体Foo:

@Entity
@Table(name="FOO")
public class Foo {

// skipping property declarations

@OneToOne
@PrimaryKeyJoinColumn(name = "FOO_ID")
@Fetch(FetchMode.JOIN)
public getFooDerivedData() {
    return fooDerivedData;
}

实体FooDerivedData

@Entity
@Table(name = "FOO_DERIVED_VW")
@Immutable
public class FooDerivedData {

    @Id
    @Column(name = "FOO_ID")
    long fooId;

    @Column(name = "FOO_COUNT")
    private Integer fooCount;

    @Column(name = "FOO_SUM")
    private BigDecimal fooSum;


    // Getters left out here

我正在使用JPA Criteria API(Hibernate是JPA实现),我需要在FooDerivedData中加载Foo的实例。默认情况下,这是急切获取的,但是我希望它使用内部联接,而不是FooDerivedData的每个实例的单独select语句。我成功地能够针对FooDerivedData添加内部联接。

CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> root = criteriaQuery.from(Foo.class);
root.join("fooDerivedData");
Predicate p = getPredicate(); // details omitted here
criteriaQuery.select(root).where(p);

虽然我可以从日志中的SQL中看到为FOO_DERIVED_VW添加了内部联接,但是没有选择任何列。对于Foo的每个实例,我仍然需要一个单独的select语句来获取我已经可用的数据。

目前查询是这样的:

select f.foo_id, f.foo_bar from from FOO f
inner join FOO_DERIVED_VW d on d.foo_id = f.foo_id;
select d.foo_id, d.foo_count, d.foo_sum from FOO_DERIVED_VW d where foo_id = ?;
select d.foo_id, d.foo_count, d.foo_sum from FOO_DERIVED_VW d where foo_id = ?;

请注意,我没有从已加入的FOO_DERIVED_VW中选择任何数据,并且此数据正在通过其他数据库命中来实现。我希望查询是这样的:

select f.foo_id, f.foo_bar, d.foo_count, d.foo_sum from from FOO f
inner join FOO_DERIVED_VW d on d.foo_id = f.foo_id;

如何在Criteria API中从已加入的实体中选择属性?我可以指示javax.persistence.criteria.Root来选择我加入的属性吗?

我尝试从连接更改为提取,或者我指定连接类型的提取。在任何一种情况下,它都失败了Hibernate QueryException。

Root<Foo> root = criteriaQuery.from(Foo.class);
root.fetch("fooDerivedData");
  

引起:org.hibernate.QueryException:查询指定的连接   获取,但获取的关联的所有者不存在   选择列表

2 个答案:

答案 0 :(得分:1)

我认为你有几个选择。如果您的where条件不使用连接表中的任何列,那么您尝试的提取应该如下工作:

CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> root = criteriaQuery.from(Foo.class);
root.fetch("fooDerivedData");
Predicate p = getPredicate(); // details omitted here
criteriaQuery.select(root).where(p);

如果你的谓词确实包含来自连接表的列,那么你可以像你一样加入(获取当前不会为此工作),然后通过添加它来指定动态实体图(从JPA 2.1开始)你有什么:

CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> root = criteriaQuery.from(Foo.class);
root.join("fooDerivedData");
Predicate p = getPredicate(); // details omitted here
criteriaQuery.select(root).where(p);
EntityGraph<Foo> fetchGraph = entityManager.createEntityGraph(Foo.class);
fetchGraph.addSubgraph("fooDerivedData");
EntityManager.createQuery(criteriaQuery).setHint("javax.persistence.loadgraph", fetchGraph);

答案 1 :(得分:0)

我认为您不需要为FetchMode指定getFooDerivedData(),因为OneToOne关系的默认提取类型为EAGER。希望这有帮助!