1. 程式人生 > >《Hibernate快速開始》Query /Criteria

《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;
}
}

&nbsp;

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();