2016-11-07 78 views
0

我试图找到所有具有一些嵌套元素和嵌套元素的实体,并且我需要通过这些集合的属性来找到它。按标准api搜索集合字段的嵌套属性

这将是这样的

class A{ 
    private B b; 
} 

class B{ 
    private Collection<C> cCol; 
} 

class C{ 
    private String name; 
} 

所以我想所有有具有名称匹配给定参数C B元素的A元素。

不确定如何使用JPA Critieria API执行此操作。我知道JPQL中存在predicate或MEMEBER OF,但我需要通过collection中元素的属性进行搜索,而不是集合成员。

尝试的东西像root.get(a.b.c.name),并与root.fetch(a.b)root.fetch(b.c)但总是结束了与非法API使用

回答

3

我想要一个一个具有B元素的元素,其中C元素的名称与给定的参数相匹配。

当试图浏览条件API时,我发现首先编写JPQL查询非常有帮助。那就是:

SELECT a 
FROM A a 
WHERE EXISTS(
    SELECT c FROM a.b b JOIN b.cCol c WHERE c.name = 'condition' 
) 

现在的标准API逐渐明朗(如果这是不可能的):

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<A> aQuery = cb.createQuery(A.class); 
Root<A> a = aQuery.from(A.class); 

Subquery<C> cSubquery = aQuery.subquery(C.class); 
Root<A> aSubroot = cSubquery.correlate(a); 
Join<A, B> b = aSubroot.join("b"); // "b" is the name of the property of A that points to B 
Join<B, C> c = b.join("cCol"); // "cCol" is the name of the property of C that holds the related C objects 

cSubquery.select(c); 
cSubquery.where(cb.equal(c.get("name"), "XXXXXXX")); 

aQuery.where(cb.exists(cSubquery)); 

TypedQuery<A> aTypedQuery = em.createQuery(aQuery); 
aTypedQuery.getResultList(); 

的Java变量的名称是一样的,在JPQL,例如对应于JPQL FROM a.b b

+0

'aQuery.distinct(true).where(cb.equal(root.get(“b”)。get(“cCol”)。get(“name”),searchString))''也应该给出相同的结果需要一个子查询 - 等价的JPQL查询应该是'SELECT DISTINCT a from a a JOIN ab b JOIN b.cCol c WHERE c.name =:searchString' – mata

+0

我更喜欢子查询而不是DISTINCT JOIN的原因是性能。虽然我不是这方面的专家,但下面是一些支持它的资源:[(1)](https://danmartensen.svbtle.com/sql-performance-of-join-and-where-exists),[(2 )](http://www.toadworld.com/platforms/oracle/w/wiki/4773.exists-versus-distinct),[(3)](http://stackoverflow.com/questions/13692992/join-与存在性能),[(4)](http://stackoverflow.com/questions/12201885/how-to-determine-what-is-more-effective-distinct-or-where-exists)。当然,实际结果和性能增益取决于确切的用例。 –

+0

工程就像一个魅力,谢谢! – Nadir

1

一些例外的下面应该工作

root.get("a").get("b").get("name") 

How to create specification using JpaSpecificationExecutor by combining tables?

+1

从使用的字段名称应该是'root.get(“b”)。get(“cCol”)。get(“name”)'(假设'root'是'根')。 – mata

+0

不幸的是,这与IllegalStateException失败:非法尝试取消引用基本类型的路径源[null.b.cCol] – Nadir

+0

@Nadir - 你应该发布更多的代码,试图创建查询 – mata