跳轉到內容

Java 持久化/Criteria

來自 Wikibooks,開放的書籍,開放的世界

Criteria API

[編輯 | 編輯原始碼]

Java 持久化 Criteria API 用於透過構建基於物件的查詢定義物件來定義動態查詢,而不是使用 JPQL 的基於字串的方法。Criteria API 允許以程式設計方式構建動態查詢,與基於字串的第 4 代語言相比,它提供了更好的 Java 語言整合。

Criteria API 有兩種模式,型別限制模式和非型別模式。型別限制模式使用一組 JPA 元模型生成的類來定義類的可查詢屬性,請參見元模型。非型別模式使用字串引用類的屬性。

Criteria API 僅用於動態查詢,不能用於元資料或命名查詢。Criteria 查詢是動態查詢,因此不如靜態命名查詢或甚至動態引數化 JPQL(在某些 JPA 提供程式中可能受益於解析快取)那樣高效。

Criteria API 添加於 JPA 2.0 中。

Criteria API 刪除和更新支援添加於 JPA 2.1 中。

CriteriaBuilder

[編輯 | 編輯原始碼]

CriteriaBuilder是進入 Criteria API 的主要介面。一個CriteriaBuilder從一個EntityManager或一個EntityManagerFactory使用getCriteriaBuilder()API。CriteriaBuilder用於構造CriteriaQuery物件及其表示式。Criteria API 目前僅支援 select 查詢。

CriteriaBuilder定義了用於建立CriteriaQuery物件的 API

  • createQuery()- 建立一個CriteriaQuery.
  • createQuery(Class)- 建立一個CriteriaQuery使用泛型來避免強制轉換結果類。
  • createTupleQuery()- 建立一個CriteriaQuery返回類似於 map 的Tuple物件,而不是用於多選查詢的物件陣列。請參見Tuple Queries
  • createCriteriaDelete(Class)- 建立一個CriteriaDelete直接在資料庫上刪除一批物件(JPA 2.1)。
  • createCriteriaUpdate(Class)- 建立一個CriteriaUpdate直接在資料庫上更新一批物件(JPA 2.1)。

CriteriaBuilder還定義了所有支援的比較運算和函式,這些運算和函式用於定義查詢的子句。

CriteriaQuery

[編輯 | 編輯原始碼]

CriteriaQuery定義了資料庫 select 查詢。一個CriteriaQuery對 JPQL select 查詢的所有子句進行建模。來自一個CriteriaQuery的元素不能用於其他CriteriaQuerys。一個CriteriaQueryEntityManager createQuery()API 一起使用以建立 JPAQuery.

CriteriaQuery定義了以下子句和選項

  • distinct(boolean)- 定義查詢是否應該過濾重複結果(預設為 false)。如果使用與集合關係的連線,則應使用 distinct 以避免重複結果。
  • from(Class)- 為實體類定義並返回查詢的 from 子句中的一個元素。查詢至少需要一個 from 元素才能有效。
  • from(EntityType)- 為元模型實體型別定義並返回查詢的 from 子句中的一個元素。查詢至少需要一個 from 元素才能有效。
  • select(Selection)- 定義查詢的 select 子句。如果未設定,則預設情況下將選擇第一個根。
  • multiselect(Selection...), multiselect(List<Selection>)- 定義多選查詢。
  • where(Expression), where(Predicate...)- 定義查詢的 where 子句。預設情況下,將選擇該類所有例項。
  • orderBy(Order...), orderBy(List<Order>)- 定義查詢的 order 子句。預設情況下,結果未排序。
  • groupBy(Expression...), groupBy(List<Expression>)- 定義查詢的 group by 子句。預設情況下,結果未分組。
  • having(Expression), having(Predicate...)- 定義查詢的 having 子句。Having 允許對分組結果進行過濾。
  • subQuery(Class)- 建立一個subQuery用於其他子句之一。

Expressions, Predicates, Order元素使用CriteriaBuilderAPI 定義,並從from Root元素派生表示式。

CriteriaQuery 示例
[編輯 | 編輯原始碼]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Query for a List of objects.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.where(criteriaBuilder.greaterThan(employee.get("salary"), 100000));
Query query = entityManager.createQuery(criteriaQuery);
List<Employee> result = query.getResultList();

// Query for a single object.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.where(criteriaBuilder.equal(employee.get("id"), criteriaBuilder.parameter(Long.class, "id")));
Query query = entityManager.createQuery(criteriaQuery);
query.setParameter("id", id);
Employee result2 = (Employee)query.getSingleResult();

// Query for a single data element.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(criteriaBuilder.max(employee.get("salary")));
Query query = entityManager.createQuery(criteriaQuery);
BigDecimal result3 = (BigDecimal)query.getSingleResult();

// Query for a List of data elements.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(employee.get("firstName"));
Query query = entityManager.createQuery(criteriaQuery);
List<String> result4 = query.getResultList();

// Query for a List of element arrays.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.multiselect(employee.get("firstName"), employee.get("lastName"));
Query query = entityManager.createQuery(criteriaQuery);
List<Object[]> result5 = query.getResultList();

一個選擇定義了查詢選擇的內容。一個選擇可以是任何物件表示式、屬性表示式、函式、子選擇、建構函式或聚合函式。一個別名可以為一個選擇使用alias()API。

聚合函式

[編輯 | 編輯原始碼]

聚合函式可以包含有關一組物件的彙總資訊。這些函式可以用來返回單個結果,也可以與groupBy一起使用來返回多個結果。

聚合函式定義在CriteriaBuilder上,幷包括

  • max(Expression)- 返回所有結果的最大值。用於數值型別。
  • greatest(Expression)- 返回所有結果的最大值。用於非數值型別。
  • min(Expression)- 返回所有結果的最小值。用於數值型別。
  • least(Expression)- 返回所有結果的最小值。用於非數值型別。
  • avg(Expression)- 返回所有結果的平均值。一個Double被返回。
  • sum(Expression)- 返回所有結果的總和。
  • sumAsLong(Expression)- 返回所有結果的總和。一個Long被返回。
  • sumAsDouble(Expression)- 返回所有結果的總和。一個Double被返回。
  • count(Expression)- 返回所有結果的計數。null值不計入計數。一個Long被返回。
  • countDistinct(Expression)- 返回所有不同結果的計數。null值不計入計數。一個Long被返回。
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Count the total employees
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(criteriaBuilder.count(employee));
Query query = entityManager.createQuery(criteriaQuery);
Long result = query.getSingleResult();

// Maximum salary
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(criteriaBuilder.max(employee.get("salary"));
Query query = entityManager.createQuery(criteriaQuery);
Long result = query.getSingleResult();

建構函式

[編輯 | 編輯原始碼]

construct運算子在CriteriaBuilder上可以使用類和值從 Criteria 查詢返回資料物件。這些將不是託管物件,並且該類必須定義一個與引數和型別匹配的建構函式。建構函式查詢可用於選擇物件上的部分資料或報告資料,並返回類例項而不是物件陣列或元組。

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(criteriaBuilder.construct(EmpReport.class, employee.get("firstName"), employee.get("lastName"), employee.get("salary")));
Query query = entityManager.createQuery(criteriaQuery);
List<EmpReport> result = query.getResultList();

查詢的 from 子句定義了要查詢的內容。from 子句使用fromAPI onCriteriaQuery。一個Root物件從from返回,代表查詢上下文中的物件。一個Root也實現了From,並且Path. Fromfrom 子句中定義了一個變數,並允許聯接。Path定義了任何屬性值,並允許遍歷巢狀屬性。

Root employee = criteriaQuery.from(Employee.class);

Criteria 查詢允許多個根級物件。在執行此操作時應謹慎,因為它會導致兩個表的笛卡爾積。where 子句應確保兩個物件以某種方式聯接。

// Select the employees and the mailing addresses that have the same address.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
Root address = criteriaQuery.from(MailingAddress.class);
criteriaQuery.multiselect(employee, address);
criteriaQuery.where(criteriaBuilder.equal(employee.get("address"), address.get("address"));
Query query = entityManager.createQuery(criteriaQuery);
List<Object[]> result = query.getResultList();

一個join操作可用於From物件以獲取要用於查詢的關係。join並不意味著將獲取關係,要獲取結果中相關物件,請使用fetch操作。

Root employee = criteriaQuery.from(Employee.class);
Join address = employee.join("address");
criteriaQuery.where(criteriaBuilder.equal(address.get("city"), city);

join操作可用於 OneToOne、ManyToOne、OneToMany、ManyToMany 和 ElementCollection 對映。當與集合關係一起使用時,可以多次聯接相同的關係以查詢多個獨立的值。

// All employees who work on both projects.
Root employee = criteriaQuery.from(Employee.class);
Join p = employee.join("projects");
Join p2 = employee.join("projects");
criteriaQuery.where(criteriaBuilder.and(criteriaBuilder.equal(p.get("name"), projectName1), criteriaBuilder.equal(p2.get("name"), projectName2));

fetch操作可用於From物件以在單個查詢中獲取相關物件。這避免了對每個物件的每個關係的額外查詢,並確保如果關係為 LAZY,則已獲取關係。

Root employee = criteriaQuery.from(Employee.class);
Fetch address = employee.fetch("address");
criteriaQuery.select(employee);

在使用獲取where 子句中應謹慎,因為它會影響結果物件關係的返回資料。物件通常應始終具有相同的資料,無論它們如何被查詢,這對快取和一致性很重要。這隻有在別名用於 where 子句中的集合關係以過濾將要獲取的相關物件時才會成為問題。不應執行此操作,但有時是可取的,在這種情況下,查詢應確保已將其設定為繞過快取。

預設情況下joinfetch是內部聯接。這意味著沒有關係的結果將從查詢結果中過濾掉。為了避免這種情況,可以使用 LEFT 將聯接定義為外部聯接JoinType作為joinfetch操作的引數。

Root employee = criteriaQuery.from(Employee.class);
Join address = employee.join("address", JoinType.LEFT);
criteriaQuery.order(address.get("city"));

查詢的 order by 子句定義了查詢結果的排序方式。order by 子句使用orderByAPI onCriteriaQuery定義。只有Order物件可以傳遞給orderBy,並且從CriteriaBuilder使用ascdescAPI。

// Order by the last and first names.
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.orderBy(criteriaBuilder.desc(employee.get("lastName")), criteriaBuilder.asc(employee.get("firstName")));
// Order by the last name, ignoring case.
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.orderBy(criteriaBuilder.asc(criteriaBuilder.upper(employee.get("lastName"))));
// Order by the address object (orders by its id).
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.orderBy(criteriaBuilder.asc(employee.get("address")));

分組依據

[編輯 | 編輯原始碼]

查詢的 group by 子句允許對一組物件計算彙總資訊。group by 通常與聚合函式一起使用。group by 子句使用groupByAPI onCriteriaQuery定義,其中包含任何有效的Expression物件。

// Select the average salaries grouped by city.
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.multiselect(criteriaBuilder.avg(employee.<Number>get("salary")), employee.get("address").get("city"));
criteriaQuery.groupBy(employee.get("address").get("city"));
// Select the average salaries grouped by city, ordered by the average salary.
Root employee = criteriaQuery.from(Employee.class);
Expression avg = criteriaBuilder.avg(employee.<Number>get("salary"));
criteriaQuery.multiselect(avg, employee.get("address").get("city"));
criteriaQuery.groupBy(employee.get("address").get("city"));
criteriaQuery.orderBy(criteriaBuilder.asc(avg));
// Select employees and the count of their number of projects.
Root employee = criteriaQuery.from(Employee.class);
Expression project = employee.join("projects", JoinType.LEFT);
criteriaQuery.multiselect(e, criteriaBuilder.count(project));
criteriaQuery.groupBy(employee);

查詢的 having 子句允許過濾 group by 的結果。having 子句使用havingAPI onCriteriaQuery定義,其中包含任何Predicate物件。

// Select the average salaries grouped by city, only including cities with average salaries over 100000.
Root employee = criteriaQuery.from(Employee.class);
Expression avg = criteriaBuilder.avg(employee.<Number>get("salary"));
criteriaQuery.multiselect(avg, employee.get("address").get("city"));
criteriaQuery.groupBy(employee.get("address").get("city"));
criteriaQuery.having(criteriaBuilder.greaterThan(avg, 100000));

CriteriaUpdate (JPA 2.1)

[編輯 | 編輯原始碼]

CriteriaUpdate定義了資料庫更新查詢。一個CriteriaUpdate對 JPQL 更新查詢的所有子句進行建模。來自一個CriteriaUpdate的元素不能用於其他CriteriaUpdates。一個CriteriaUpdateEntityManager createQuery()API 一起使用以建立 JPAQuery。Criteria 更新只能用於批處理更新。對於對物件的定期更新,應透過事務中的 EntityManager 讀取物件,並在 Java 中修改物件,並提交更改。

CriteriaUpdate定義了以下子句和選項

  • set(String, Object), set(Path, Object), set(Path, Expression)- 定義更新的 set 子句。
  • where(Expression), where(Predicate...)- 定義更新的 where 子句。預設情況下,更新類的所有例項。

Expressions, Predicates元素使用CriteriaBuilderAPI 定義,並從from Root元素派生表示式。

CriteriaUpdate 示例
[編輯 | 編輯原始碼]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Updates the salary to 90,000 of all Employee's making more than 100,000.
CriteriaUpdate update = criteriaBuilder.createCriteriaUpdate(Employee.class);
Root employee = update.from(Employee.class);
update.set("salary", 90000);
update.where(criteriaBuilder.greaterThan(employee.get("salary"), 100000));
Query query = entityManager.createQuery(update);
int rowCount = query.executeUpdate();

// Gives all Employees a 10% raise.
CriteriaUpdate update = criteriaBuilder.createCriteriaUpdate(Employee.class);
Root employee = update.from(Employee.class);
update.set(employee.get("salary"), criteriaBuilder.sum(employee.get("salary"), criteriaBuilder.quot(employee.get("salary"), 10));
Query query = entityManager.createQuery(update);
int rowCount = query.executeUpdate();

CriteriaDelete (JPA 2.1)

[編輯 | 編輯原始碼]

CriteriaDelete定義了資料庫刪除查詢。一個CriteriaDelete對 JPQL 刪除查詢的所有子句進行建模。來自一個CriteriaDelete的元素不能用於其他CriteriaDelete。一個CriteriaDeleteEntityManager createQuery()API 一起使用以建立 JPAQuery. CriteriaDelete只能用於批處理刪除。對於物件的定期刪除,應透過事務中的 EntityManager 讀取物件,並透過 remove() API 刪除物件,並提交更改。

CriteriaDelete定義了以下子句和選項

  • where(Expression), where(Predicate...)- 定義刪除的 where 子句。預設情況下,刪除類的所有例項。

Expressions, Predicates元素使用CriteriaBuilderAPI 定義,並從from Root元素派生表示式。

CriteriaDelete 示例
[編輯 | 編輯原始碼]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Deletes all Employee's making more than 100,000.
CriteriaDelete delete = criteriaBuilder.createCriteriaDelete(Employee.class);
Root employee = delete.from(Employee.class);
delete.where(criteriaBuilder.greaterThan(employee.get("salary"), 100000));
Query query = entityManager.createQuery(delete);
int rowCount = query.executeUpdate();

// Deletes all Employees.
CriteriaDelete delete = criteriaBuilder.createCriteriaDelete(Employee.class);
Root employee = delete.from(Employee.class);
Query query = entityManager.createQuery(delete);
int rowCount = query.executeUpdate();

where 子句通常是查詢的主要部分,因為它定義了過濾返回內容的條件(謂詞)。where 子句使用whereAPI onCriteriaQuery定義,其中包含任何Predicate物件定義。一個Predicate使用比較運算子或對CriteriaBuilder的邏輯運算子獲得。該isNull, isNotNull,並且in操作也可以在Expression的邏輯運算子獲得。該not操作也可以在Predicate

上定義的比較運算子CriteriaBuilder

[編輯 | 編輯原始碼]
操作 描述 示例
equal, notEqual equal
criteriaBuilder.equal(employee.get("firstName"), "Bob")
lessThan, lt 小於
criteriaBuilder.lessThan(employee.get("salary"), 100000)
greaterThan, gt 大於
criteriaBuilder.greaterThan(employee.get("salary"), criteriaBuilder.parameter(Integer.class, "sal"))
lessThanOrEqualTo, le 小於或等於
criteriaBuilder.lessThanOrEqualTo(employee.get("salary"), 100000)
greaterThanOrEqualTo, ge 大於或等於
criteriaBuilder.greaterThanOrEqualTo(employee.get("salary"), criteriaBuilder.parameter(Integer.class, "sal"))
like, notLike 評估兩個字串是否匹配,'%' 和 '_' 是有效的萬用字元,並且 ESCAPE 字元是可選的
criteriaBuilder.like(employee.get("firstName"), "A%")
criteriaBuilder.notLike(employee.get("firstName"), "%._%", '.')
between 評估值是否在兩個值之間
criteriaBuilder.between(employee.<String>get("firstName"), "A", "C")
isNull 將值與 null 進行比較,資料庫可能不允許或在將 = 與 null 一起使用時產生意外結果
criteriaBuilder.isNull(employee.get("endDate"))
employee.get("endDate").isNull()
in 評估值是否包含在列表中
criteriaBuilder.in(employee.get("firstName")).value("Bob").value("Fred").value("Joe")
employee.get("firstName").in("Bob", "Fred", "Joe")
employee.get("firstName").in(criteriaBuilder.parameter(List.class, "names")

CriteriaBuilder 上定義的邏輯運算子CriteriaBuilder

[編輯 | 編輯原始碼]
操作 描述 示例
and 將兩個或多個謂詞組合在一起
criteriaBuilder.and(criteriaBuilder.equal(employee.get("firstName"), "Bob"), criteriaBuilder.equal(employee.get("lastName"), "Smith"))
or 將兩個或多個謂詞組合在一起
criteriaBuilder.or(criteriaBuilder.equal(employee.get("firstName"), "Bob"), criteriaBuilder.equal(employee.get("firstName"), "Bobby"))
not 否定謂詞
criteriaBuilder.not(criteriaBuilder.or(criteriaBuilder.equal(employee.get("firstName"), "Bob"), criteriaBuilder.equal(employee.get("firstName"), "Bobby")))
criteriaBuilder.or(criteriaBuilder.equal(employee.get("firstName"), "Bob"), criteriaBuilder.equal(employee.get("firstName"), "Bobby")).not()
連線 表示 true 的謂詞
Predicate where = criteriaBuilder.conjunction();
if (name != null) {
    where = criteriaBuilder.and(where, criteriaBuilder.equal(employee.get("firstName"), name));
}
析取 表示 false 的謂詞
Predicate where = criteriaBuilder.disjunction();
if (name != null) {
    where = criteriaBuilder.or(where, criteriaBuilder.equal(employee.get("firstName"), name));
}

子查詢

[編輯 | 編輯原始碼]

子查詢只能在 where 子句和 having 子句中使用。子查詢從CriteriaQuery使用subQuery操作建立。大多數子查詢用法將子查詢限制為返回單個結果和值,除非與CriteriaBuilder exists, all, anysome操作一起使用,或者與in操作的引數。

子查詢示例
[編輯 | 編輯原始碼]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Find all manager that only manage below-average employees.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
Subquery subQuery = criteriaQuery.subquery(Employee.class);
Root employee_2 = subQuery.from(Employee.class);
subQuery.where(criteriaBuilder.and(employee_2.get("manager").equal(e), criteriaBuilder.equal(employee_2.get("productivity"), "below average").not());
criteriaQuery.where(criteriaBuilder.exists(subQuery).not());
Query query = entityManager.createQuery(criteriaQuery)
List<Employee> = query.getResultList();

// Find the employee with the lowest salary.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
Subquery subQuery = criteriaQuery.subquery(Employee.class);
Root employee_2 = subQuery.from(Employee.class);
subQuery.select(employee_2.get("salary"));
criteriaQuery.where(criteriaBuilder.lessThan(employee.get("salary"), criteriaBuilder.all(subQuery)));
Query query = entityManager.createQuery(criteriaQuery)
List<Employee> = query.getResultList();

可以使用parameterAPI onCriteriaBuilder定義引數。JPA 定義了命名引數和位置引數。對於命名引數,指定引數型別和名稱。對於位置引數,只指定引數型別。位置引數從位置1not0.

命名引數 criteria 示例
[編輯 | 編輯原始碼]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.where(
        criteriaBuilder.equal(employee.get("firstName"), criteriaBuilder.parameter(String.class, "first")),
        criteriaBuilder.equal(employee.get("lastName"), criteriaBuilder.parameter(String.class, "last"))
    );
Query query = entityManager.createQuery(criteriaQuery)
query.setParameter("first", "Bob");
query.setParameter("last", "Smith");
List<Employee> = query.getResultList();
位置引數標準示例
[編輯 | 編輯原始碼]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.where(criteriaBuilder.equal(employee.get("firstName"), criteriaBuilder.parameter(String.class)), criteriaBuilder.equal(employee.get("lastName"), criteriaBuilder.parameter(String.class)));
Query query = entityManager.createQuery(criteriaQuery)
query.setParameter(1, "Bob");
query.setParameter(2, "Smith");
List<Employee> = query.getResultList();

Criteria API 支援一些資料庫函式。所有支援的函式都在CriteriaBuilder上定義。一些函式可能不受某些資料庫支援,因為它們不符合 SQL 標準,並且沒有等效的函式。

CriteriaBuilder資料庫函式

[編輯 | 編輯原始碼]
函式 描述 示例
diff 減法
criteriaBuilder.diff(employee.<Number>get("salary"), 1000)
sum 加法
criteriaBuilder.sum(employee.<Number>get("salary"), 1000)
prod 乘法
criteriaBuilder.prod(employee.<Number>get("salary"), 2)
quot 除法
criteriaBuilder.quot(employee.<Number>get("salary"), 2)
abs 絕對值
criteriaBuilder.abs(
    criteriaBuilder.diff(employee.<Number>get("salary"), employee.get("manager").<Number>get("salary")))
selectCase 定義一個 case 語句
criteriaBuilder.selectCase(employee.get("status")).
    when(0, "active").
    when(1, "consultant").
    otherwise("unknown")
criteriaBuilder.selectCase().
    when(criteriaBuilder.equal(employee.get("status"), 0), "active").
    when(criteriaBuilder.equal(employee.get("status"), 1), "consultant").
    otherwise("unknown")
coalesce 計算第一個非空引數的值
criteriaBuilder.coalesce(criteriaBuilder.concat(employee.<Number>get("salary"), 0)
concat 連線兩個或多個字串值
criteriaBuilder.concat(
    criteriaBuilder.concat(employee.<String>get("firstName"), " "), employee.<String>get("lastName"))
currentDate 資料庫中的當前日期
criteriaBuilder.currentDate()
currentTime 資料庫中的當前時間
criteriaBuilder.currentTime()
currentTimestamp 資料庫中的當前日期時間
criteriaBuilder.currentTimestamp()
length 字元或二進位制值的字元/位元組長度
criteriaBuilder.length(employee.<String>get("lastName"))
locate 字串在字串中的索引,可以選擇從起始索引開始
criteriaBuilder.locate("-", employee.<String>get("lastName"))
lower 將字串值轉換為小寫
criteriaBuilder.lower(employee.<String>get("lastName"))
mod 計算第一個整數除以第二個整數的餘數
criteriaBuilder.mod(employee.<Integer>get("hoursWorked"), 8)
nullif 如果第一個引數等於第二個引數,則返回 null,否則返回第一個引數
criteriaBuilder.nullif(employee.<Number>get("salary"), 0)
sqrt 計算數字的平方根
criteriaBuilder.sqrt(employee.<Number>get("salary"))
substring 字串的子字串,從索引開始,可以選擇子字串的大小
criteriaBuilder.substring(employee.<String>get("lastName"), 0, 2)
trim 從字串中修剪開頭、結尾或兩端的空格或可選的修剪字元
criteriaBuilder.trim(TrimSpec.TRAILING, employee.<String>get("lastName"))
criteriaBuilder.trim(employee.<String>get("lastName"))
criteriaBuilder.trim(TrimSpec.LEADING, '-', employee.<String>get("lastName"))
upper 將字串值轉換為大寫
criteriaBuilder.upper(employee.<String>get("lastName"))

特殊操作

[編輯 | 編輯原始碼]

Criteria API 定義了一些特殊操作,這些操作不是資料庫函式,但在 JPA 中具有特殊含義。其中一些操作是在CriteriaBuilder上定義的,而另一些則是在特定表示式介面上定義的。

Criteria API 特殊函式

[編輯 | 編輯原始碼]
函式 描述 示例
index 排序列表元素的索引,僅在對映中使用 @OrderColumn 時支援,

ListJoin介面上定義,該介面從From元素使用joinList操作獲得

Root employee = criteriaQuery.from(Employee.class);
ListJoin toDo = employee.joinList("toDoList");
criteriaQuery.multiselect(e, toDo);
criteriaQuery.where(criteriaBuilder.equal(toDo.index(), 1));
key, value 對映元素的鍵或值,在MapJoin介面上定義,該介面從From元素使用joinMap操作獲得
Root employee = criteriaQuery.from(Employee.class);
MapJoin p = employee.joinMap("priorities");
criteriaQuery.multiselect(e, p.value());
criteriaQuery.where(criteriaBuilder.equal(p.key(), "high"))
size 集合關係的大小,這將計算為子查詢,在CriteriaBuilder
criteriaBuilder.greaterThan(criteriaBuilder.size(employee.<Collection>get("managedEmployees")), 2)
isEmpty, isNotEmpty 上定義,它計算為真,如果集合關係為空或不為空,這將計算為子查詢,在CriteriaBuilder
criteriaBuilder.isEmpty(employee.<Collection>get("managedEmployees"))
isMember, isNotMember 上定義,它計算為真,如果集合關係包含該值,這將計算為子查詢,在CriteriaBuilder
criteriaBuilder.isMember("write code", employee.<Collection>get("responsibilities"))
type 繼承鑑別器值,在任何Path表示式
criteriaBuilder.equal(p.type(), LargeProject.class)
as 可用於將非型別化表示式轉換為型別化表示式,EclipseLink 還允許將繼承型別向下轉換
criteriaBuilder.mod(employee.get("id").as(Integer.class), 2)
criteriaBuilder.greaterThan(p.as(LargeProject.class).get("budget"), 1000000)
function 呼叫資料庫特定函式,在CriteriaBuilder
criteriaBuilder.greaterThan(criteriaBuilder.function("TO_NUMBER", Number.class, p.get("areaCode")), 613)

Metamodel

[編輯 | 編輯原始碼]

JPA 定義了一個元模型,它可以在執行時用於查詢有關 ORM 對映元資料的的資訊。元模型包括類對映屬性的列表,以及它們的對映型別和基數。元模型可與 Criteria API 一起使用,以替代使用字串引用類屬性。

JPA 定義了一組_類,這些類將由 JPA 提供程式或 IDE 生成,從而在編譯時訪問元模型。這允許在 Criteria API 中使用型別化的靜態變數。這可以透過在編譯時而不是在測試期間捕獲查詢問題,來減少應用程式程式碼中出現拼寫錯誤或無效查詢的可能性。但是,它確實增加了開發過程的複雜性,因為元模型靜態類需要生成併成為開發週期的一部分。

元模型標準示例
[編輯 | 編輯原始碼]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root<Employee> employee = criteriaQuery.from(entityManager.getMetamodel().entity(Employee.class));
criteriaQuery.where(criteriaBuilder.equal(employee.get(Employee_.firstName), "Bob"), criteriaBuilder.equal(employee.get(Employee_.lastName), "Smith"));
Query query = entityManager.createQuery(criteriaQuery)
List<Employee> = query.getResultList();

元組查詢

[編輯 | 編輯原始碼]

一個Tuple定義一個多選查詢結果。通常,JPA 多選查詢會返回一個物件陣列,但物件陣列不是一個非常有用的資料結構。一個Tuple是一個類似於對映的結構,它允許透過名稱或索引檢索結果。

元組查詢示例
[編輯 | 編輯原始碼]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.multiselect(employee.get("firstName").alias("first"), employee.get("lastName").alias("last"));
Query query = entityManager.createQuery(criteriaQuery);
List<Tuple> results = query.getResultList();
String first = results.get(0).get("first");
String last = results.get(0).get("last");
華夏公益教科書