Spring?JPA使用CriteriaBuilder動(dòng)態(tài)構(gòu)造查詢(xún)方式
Spring JPA使用CriteriaBuilder動(dòng)態(tài)構(gòu)造查詢(xún)
在使用Spring JPA提供的方法只能進(jìn)行簡(jiǎn)單的CRUD,如果遇到復(fù)雜的情況就需要我們動(dòng)態(tài)來(lái)構(gòu)建查詢(xún)條件了。這里我們來(lái)看使用CriteriaBuilder如何來(lái)構(gòu)造查詢(xún)。
核心代碼:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query = criteriaBuilder.createQuery(Long.class);
Root<Order> root = query.from(Order.class);
query.select(criteriaBuilder.count(root.get("id")));
Predicate predicate = criteriaBuilder.equal(root.get("id"), 1);
query.where(predicate);
Long singleResult = entityManager.createQuery(query).getSingleResult();
調(diào)用entityManager.getCriteriaBuilder()來(lái)獲取CriteriaBuilder。CriteriaBuilder可以用于創(chuàng)建CriteriaQuery、CriteriaUpdate和CriteriaDelete。除此之外類(lèi)似count、max等函數(shù)也是由CriteriaBuilder來(lái)創(chuàng)建的。其中Entitymanager可以使用@PersistenceContext注解來(lái)進(jìn)行注入。
調(diào)用criteriaBuilder.createQuery來(lái)創(chuàng)建CriteriaQuery。其中createQuery的參數(shù)是Query返回值類(lèi)型。
調(diào)用query.from(Order.class)。參數(shù)是對(duì)應(yīng)于order表的實(shí)體類(lèi),query.from類(lèi)似于sql中的from語(yǔ)句,該方法的執(zhí)行等價(jià)于sql中的from order。
調(diào)用 query.select創(chuàng)建映射。 query.select(criteriaBuilder.count(root.get(“id”)))等價(jià)于select count(id)。如果執(zhí)行query.select(root)則等價(jià)于select *。
使用CriteriaBuilder構(gòu)造查詢(xún)條件Predicate,該predicate也就是在where后面的條件子句。
將Predicate放在 query.where中。
最后執(zhí)行查詢(xún)獲取數(shù)據(jù)。
JPA CriteriaBuilder中一些運(yùn)算的使用
最近使用jpa時(shí),需要使用訂單中的金額除以單價(jià)算出每個(gè)訂單的數(shù)量,然后求和。找了好多資料才解決,在此整理一下。
首先了解一下CriteriaBuilder的一些運(yùn)算
// Create path and parameter expressions:
Expression<Integer> path = country.get("population");
Expression<Integer> param = cb.parameter(Integer.class);
// Addition (+)
Expression<Integer> sum1 = cb.sum(path, param); // expression + expression
Expression<Integer> sum2 = cb.sum(path, 1000); // expression + number
Expression<Integer> sum3 = cb.sum(1000, path); // number + expression
// Subtraction (-)
Expression<Integer> diff1 = cb.diff(path, param); // expression - expression
Expression<Integer> diff2 = cb.diff(path, 1000); // expression - number
Expression<Integer> diff3 = cb.diff(1000, path); // number - expression
// Multiplication (*)
Expression<Integer> prod1 = cb.prod(path, param); // expression * expression
Expression<Integer> prod2 = cb.prod(path, 1000); // expression * number
Expression<Integer> prod3 = cb.prod(1000, path); // number * expression
// Division (/)
Expression<Integer> quot1 = cb.quot(path, param); // expression / expression
Expression<Integer> quot2 = cb.quot(path, 1000); // expression / number
Expression<Integer> quot3 = cb.quot(1000, path); // number / expression
// Modulo (%)
Expression<Integer> mod1 = cb.mod(path, param); // expression % expression
Expression<Integer> mod2 = cb.mod(path, 1000); // expression % number
Expression<Integer> mod3 = cb.mod(1000, path); // number % expression
// Math(abs, exp, sqrt)
Expression<Integer> abs = cb.abs(param); // 求絕對(duì)值A(chǔ)BS(expression)
Expression<Integer> neg = cb.neg(path); // 求相反數(shù) -expression
Expression<Integer> sqrt = cb.sqrt(cb.literal(100)); //求平方根 SQRT(expression)
由于CriteriaBuilder提供的加減乘除方法的名字和平常使用的不太一樣,所以用了好久才找出來(lái)。
單字段求和可以直接使用
CriteriaBuilder cb = em.getCriteriaBuilder(); Expression<Number> sum = cb.sum(root.get(字段名)).alias(別名)
前邊也說(shuō)了需求是用金額(amount)除以單價(jià)(unitPrice),然后求和,所以這時(shí)需要先用amount除以u(píng)nitPrice
Expression<Number> quot = cb.quot(root.get("amount"), root.get("unitPrice"));
算出數(shù)量后就可以使用sum求和了。
cb.sum(quot)
完事之后,還需要對(duì)數(shù)據(jù)四舍五入,需要用到mysql的round方法
在CriteriaBuilder沒(méi)有找到round方法,那怎么辦呢?沒(méi)關(guān)系,CriteriaBuilder還提供了function方法,在function方法里可以直接傳方法名進(jìn)去
/**
name: 方法名
returnType: 返回類(lèi)型
arguments:表達(dá)式
**/
public <T> Expression<T> function(String name, Class<T> returnType, Expression... arguments) {
return new ParameterizedFunctionExpression(this, returnType, name, arguments);
}
調(diào)用代碼如下
Expression<BigDecimal> round = cb.function("round", BigDecimal.class, quot);
到這一步發(fā)現(xiàn),還需要保留兩位小數(shù)。可是,Expression里 沒(méi)有相關(guān)的方法。天無(wú)絕人之路,在看了cb.function()后發(fā)現(xiàn),這個(gè)方法的最后一個(gè)參數(shù)是可變參數(shù),所以上邊的代碼改成了如下
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
Expression<Integer> size = cb.size(list);
Expression<BigDecimal> round = cb.function("round", BigDecimal.class, quot,size);
至此,完成了先求兩列的商,然后對(duì)商求和的功能。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot開(kāi)發(fā)技巧之使用AOP記錄日志示例解析
這篇文章主要為大家介紹了SpringBoot開(kāi)發(fā)技巧之如何利用AOP記錄日志的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10
關(guān)于Selenium的UI自動(dòng)化測(cè)試屏幕截圖功能實(shí)例代碼
今天小編就為大家分享一篇關(guān)于Selenium的UI自動(dòng)化測(cè)試屏幕截圖功能實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05
Java InheritableThreadLocal用法詳細(xì)介紹
InheritableThreadLocal繼承了ThreadLocal,此類(lèi)擴(kuò)展了ThreadLocal以提供從父線程到子線程的值的繼承:當(dāng)創(chuàng)建子線程時(shí),子線程接收父線程具有的所有可繼承線程局部變量的初始值。 通常子線程的值與父線程的值是一致的2022-09-09
MyBatis中的XML實(shí)現(xiàn)和動(dòng)態(tài)SQL實(shí)現(xiàn)示例詳解
這篇文章主要介紹了MyBatis中的XML實(shí)現(xiàn)和動(dòng)態(tài)SQL實(shí)現(xiàn),我們可以將XML中重復(fù)出現(xiàn)的內(nèi)容提取出來(lái)放到sql標(biāo)簽中,當(dāng)需要用到sql標(biāo)簽中的內(nèi)容時(shí),用include標(biāo)簽將sql標(biāo)簽中的內(nèi)容引進(jìn)來(lái)即可,感興趣的朋友跟隨小編一起看看吧2024-02-02

