《Hibernate快速開始》Query /Criteria
該Person_.name引用的是JPA元模型引用靜態形式的示例。我們將在本章中專門使用該結構。有關JPA靜態元模型的更多詳細資訊,請參閱Hibernate JPA元模型生成器的文件。
選擇一個表示式
選擇表示式的最簡單的形式是從實體中選擇一個特定的屬性。但是這個表示式也可能會代表聚合,數學運算等。
示例2.選擇屬性
CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<String> criteria = builder.createQuery( String.class ); Root<Person> root = criteria.from( Person.class ); criteria.select( root.get( Person_.nickName ) ); criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) ); List<String> nickNames = entityManager.createQuery( criteria ).getResultList();
在這個例子中,查詢是鍵入進來的,因為預期的結果型別是java.lang.String(Person#nickName屬性的型別java.lang.String)。因為一個查詢可能包含對Person實體的多個引用,所以屬性的引用始終需要進行限定。這是通過呼叫Root#get方法完成的。
選擇多個值
實際上有幾種不同的方式可以使用criteria 查詢來選擇多個值。我們將在這裡探索兩個選項,但另一種推薦方法是使用元組criteria 查詢中描述的元組,或者考慮一個包裝器查詢,請參閱選擇包裝器以獲取詳細資訊。
示例3.選擇陣列
CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class ); Root<Person> root = criteria.from( Person.class ); Path<Long> idPath = root.get( Person_.id ); Path<String> nickNamePath = root.get( Person_.nickName); criteria.select( builder.array( idPath, nickNamePath ) ); criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) ); List<Object[]> idAndNickNames = entityManager.createQuery( criteria ).getResultList();
從技術上講,這被分類為一個型別化的查詢,但是從處理結果可以看出這是一種誤導。無論如何,這裡的預期結果型別是陣列。
然後,該示例使用javax.persistence.criteria.CriteriaBuilder的陣列方法,它將單個選擇明確地結合到javax.persistence.criteria.CompoundSelection。
例子4.使用multiselect選擇一個數組
CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class ); Root<Person> root = criteria.from( Person.class ); Path<Long> idPath = root.get( Person_.id ); Path<String> nickNamePath = root.get( Person_.nickName); criteria.multiselect( idPath, nickNamePath ); criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) ); List<Object[]> idAndNickNames = entityManager.createQuery( criteria ).getResultList();
就像我們在選擇一個數組中看到的那樣,我們有一個型別化的criteria 查詢返回一個Object陣列。兩個查詢在功能上都是等價的。第二個示例使用的multiselect()方法的行為稍有不同,這是基於在首次構建criteria 查詢時給出的型別,但在這種情況下,它表示選擇並返回一個Object []。
選擇一個包裝
選擇多個值的另一種方法是改為選擇一個將“包裝”多個值的物件。回到那裡的示例查詢,而不是返回[Person#id,Person#nickName]的陣列,而是宣告一個包含這些值的類並將其用作返回物件。
例5.選擇一個包裝
public class PersonWrapper { private final Long id; private final String nickName; public PersonWrapper(Long id, String nickName) { this.id = id; this.nickName = nickName; } public Long getId() { return id; } public String getNickName() { return nickName; } } CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<PersonWrapper> criteria = builder.createQuery( PersonWrapper.class ); Root<Person> root = criteria.from( Person.class ); Path<Long> idPath = root.get( Person_.id ); Path<String> nickNamePath = root.get( Person_.nickName); criteria.select( builder.construct( PersonWrapper.class, idPath, nickNamePath ) ); criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) ); List<PersonWrapper> wrappers = entityManager.createQuery( criteria ).getResultList();
首先,我們看到我們將用來包裝結果值的包裝物件的簡單定義。具體來說,請注意建構函式及其引數型別。由於我們將返回PersonWrapper物件,因此我們將其PersonWrapper用作我們的criteria 查詢的型別。
這個例子演示了javax.persistence.criteria.CriteriaBuilder用於構建包裝表示式的方法構造的使用。對於結果中的每一行,我們都說我們希望PersonWrapper通過匹配的建構函式例項化剩下的引數。這個包裝表示式然後作為選擇傳遞。
元組criteria 查詢
選擇多個值的更好方法是使用包裝器(我們在選擇包裝器中看到的)或使用javax.persistence.Tuple代理。
例子6.選擇一個元組
CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Tuple> criteria = builder.createQuery( Tuple.class ); Root<Person> root = criteria.from( Person.class ); Path<Long> idPath = root.get( Person_.id ); Path<String> nickNamePath = root.get( Person_.nickName); criteria.multiselect( idPath, nickNamePath ); criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) ); List<Tuple> tuples = entityManager.createQuery( criteria ).getResultList(); for ( Tuple tuple : tuples ) { Long id = tuple.get( idPath ); String nickName = tuple.get( nickNamePath ); } //or using indices for ( Tuple tuple : tuples ) { Long id = (Long) tuple.get( 0 ); String nickName = (String) tuple.get( 1 ); }
這個例子說明了通過訪問javax.persistence.Tuple介面的查詢結果。這個例子使用了顯式createTupleQuery()的javax.persistence.criteria.CriteriaBuilder方法。另一種方法是使用createQuery( Tuple.class )。
我們再次看到使用該multiselect()方法,就像在Selecting an array using multiselect.。這裡的區別在於,我們定義javax.persistence.criteria.CriteriaQuery的型別是javax.persistence.Tuple這樣的,在這種情況下,複合選擇被解釋為元組元素。javax.persistence.Tuple契約提供了三種訪問下層元素的形式:
型別
在Selecting a tuple 的例子說明這種形式的訪問tuple.get( idPath )和tuple.get( nickNamePath )呼叫。這允許基於javax.persistence.TupleElement用於構建criteria的表示式對基礎元組值進行型別訪問。
位置
允許根據位置訪問基礎元組值。簡單的Object get(int position)表單與 Selecting an array和 Selecting an array using multiselect.所示的訪問非常相似。所述<X> X得到(INT position),Class<X>型形式允許鍵入的位置訪問, 而是基於顯式提供型別的元組值的型別必須是可分配給。
別名
允許基於(可選)分配的別名訪問基礎元組值。示例查詢不適用別名。別名將通過別名方法應用於javax.persistence.criteria.Selection。就像通過positional訪問,同時存在一個型別(Object get(String alias))和無型別(<X> X get(String alias)), Class<X> 型形式。
FROM子句
一個CriteriaQuery物件定義了一個或多個實體,可嵌入或基本抽象模式型別的查詢。查詢的根物件是實體,通過導航可以實現其他型別的實體。
– JPA規範,第6.5.2 Query Roots,第262頁
FROM子句(roots, joins, paths)的所有單獨部分都實現了javax.persistence.criteria.From介面。
根
根定義所有連線,路徑和屬性在查詢中可用的基礎。根始終是一個實體型別。定義根,並通過過載 javax.persistence.criteria.CriteriaQuery方法將其新增到criteria.
示例7.Root 方法
<X> Root<X> from( Class<X> ); <X> Root<X> from( EntityType<X> );
例子8.新增一個root例子
CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Person> criteria = builder.createQuery( Person.class ); Root<Person> root = criteria.from( Person.class );
Criteria 查詢可以定義多個根,其作用是在新新增的根和其他根之間建立笛卡爾積。以下是定義實體Person和Partner實體之間的笛卡爾乘積的示例:
例子9.新增多個根例子
CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Tuple> criteria = builder.createQuery( Tuple.class ); Root<Person> personRoot = criteria.from( Person.class ); Root<Partner> partnerRoot = criteria.from( Partner.class ); criteria.multiselect( personRoot, partnerRoot ); Predicate personRestriction = builder.and( builder.equal( personRoot.get( Person_.address ), address ), builder.isNotEmpty( personRoot.get( Person_.phones ) ) ); Predicate partnerRestriction = builder.and( builder.like( partnerRoot.get( Partner_.name ), prefix ), builder.equal( partnerRoot.get( Partner_.version ), 0 ) ); criteria.where( builder.and( personRestriction, partnerRestriction ) ); List<Tuple> tuples = entityManager.createQuery( criteria ).getResultList();