摘要:根據區域部門學科類別查詢出符合條件的考評人員。繼承接口我們的考評員倉庫原繼承,為了實現可以復雜查詢,繼承接口。實現規格接口為了規范,我們建了一個的查詢規格的包,將所有生成查詢規格的類放入該包中。
SpringData
Spring項目中,我們使用JPA進行查詢,只需簡單地繼承SpringData提供的接口即可實現強大的數據查詢功能。
之前的強檢器具統計管理用的僅僅是單表查詢,理解不深,這次開發的考評員綜合查詢涉及到了多個實體間的查詢,值得學習,特此記錄。
以下是ER圖。
管理部門選擇本部門或其管轄的部門中的某人員作為該部門的考評人員。根據區域、部門、學科類別查詢出符合條件的考評人員。
概述復雜查詢,我們就需要SpringData提供的JpaSpecificationExecutor接口,這是該接口的源代碼。
public interface JpaSpecificationExecutor{ /** * Returns a single entity matching the given {@link Specification}. * * @param spec * @return */ T findOne(Specification spec); /** * Returns all entities matching the given {@link Specification}. * * @param spec * @return */ List findAll(Specification spec); /** * Returns a {@link Page} of entities matching the given {@link Specification}. * * @param spec * @param pageable * @return */ Page findAll(Specification spec, Pageable pageable); /** * Returns all entities matching the given {@link Specification} and {@link Sort}. * * @param spec * @param sort * @return */ List findAll(Specification spec, Sort sort); /** * Returns the number of instances that the given {@link Specification} will return. * * @param spec the {@link Specification} to count instances for * @return the number of instances */ long count(Specification spec); }
該接口中聲明的方法都有一個共同的參數:Specification,翻譯過來就是規范的意思。
這是Specification接口源代碼。
public interface Specification{ /** * Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given * {@link Root} and {@link CriteriaQuery}. * * @param root * @param query * @return a {@link Predicate}, must not be {@literal null}. */ Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb); }
Specification接口中有一個toPredicate方法,看不懂代碼我們可以看注釋。
Creates a WHERE clause for a query of the referenced entity in form of a {Predicate}
用謂詞的形式為引用的實體創建一個WHERE語句。
到這里,我們應該明白了這個查詢的原理:我們先生成我們需要的謂語,然后用toPredicate將謂語生成為where語句,最后再使用我們Specification類型的where語句作為參數用JpaSpecificationExecutor接口中定義的方法進行查詢。
繼承JpaSpecificationExecutor接口public interface ExaminerRepository extends CrudRepository, JpaSpecificationExecutor { }
我們的考評員倉庫原繼承CrudRepository,為了實現可以復雜查詢,繼承JpaSpecificationExecutor接口。
實現規格接口為了規范,我們建了一個spec的查詢規格的包,將所有生成查詢規格的類放入該包中。
/** * @author zhangxishuo on 2018/5/26 * 考評人員查詢規格 */ public class ExaminerSpecs { // 日志 private static final Logger logger = Logger.getLogger(ExaminerSpecs.class); public static Specificationbase(Department userDepartment, final Map map) { return new Specification () { @Override public Predicate toPredicate(Root root, CriteriaQuery> criteriaQuery, CriteriaBuilder criteriaBuilder) { return null; } }; } }
我們在這個類中寫了一個base方法,用于根據傳入的參數生成一個查詢規格。
return語句中,我們new了一個接口,然后在new這個接口的同時對這個接口進行實現,實現接口中的toPredicate方法。
toPredicate中的三個參數意義。Root:查詢的模型;CriteriaQuery:標準查詢,用于查詢的;CriteriaBuilder:標準構建,用戶構建查詢語句的。
大家不要去糾結是直接new接口然后在花括號中實現還是寫一個類實現接口然后再去new?
這里說一下我自己的理解。其實這主要是看實際需要,如果這個接口的實現類需要被好多個其他類調用,為了代碼的復用,我們就會寫一個類去實現接口,就像我們后臺MVC架構的業務邏輯層,因為同一個方法可能會被好多個控制器進行調用,所以我們建一個Service接口,再建立一個Service接口實現類,然后其他類需要時進行Autowire。
如果我們的方法不需要復用,那Android代碼就是我們最好的例子(Android中大量使用了new接口然后在new時去實現的寫法)。
public class MyActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.content_layout_id); final Button button = findViewById(R.id.button_id); button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // Code here executes on main thread after user presses button } }); } }
這是Android官方文檔中對按鈕添加點擊事件的示例代碼,我們看到這里的View.OnClickListener()就是在new的時候再去實現的。其實這也不難理解,打開我們每天用的APP,幾乎每個按鈕,每個視圖的功能都是不一樣的,所以不需要進行代碼復用。
構建謂語謂語是什么呢?按我的理解,一個謂語就是一個條件。
logger.debug("構建謂語,人員的部門的區域的id等于map中區域的id"); Predicate districtPredicate = criteriaBuilder .equal(root.join("qualifier") .join("department") .join("district") .get("id") .as(Long.class), ((District) map.get("district")) .getId());
我們使用criteriaBuilder的equal方法構建了一個等于的條件(或謂語),該條件要求考評員(root)的人員的部門的區域的id轉化為Long類型的結果與傳入的區域的id相等。
類似的寫法,我們可以構建出部門和學科的謂語。
連接謂語謂語創建完了,我們還需要將這些謂語進行連接。
這里我們需要用到and條件,即區域符合且部門符合且學科類別符合。
為了方便構建,這里參考之前的項目代碼構建了一個用and拼接謂語的方法。
private Predicate predicate = null; private CriteriaBuilder criteriaBuilder; // 設置and謂語.注意,這里只能設置and關系的謂語,如果謂語為OR,則需要手動設置 private void andPredicate(Predicate predicate) { // 如果傳入的謂語不為空 if (null != predicate) { if (null == this.predicate) { // 如果該方法之前沒有謂語,則直接賦值 this.predicate = predicate; } else { // 如果之前有謂語。則使用criteriaBuilder的與將已有謂語和新謂語用and連接 this.predicate = this.criteriaBuilder.and(this.predicate, predicate); } } }
這幾行代碼就體現了一名優秀軟件工程師的素養,優秀的人在寫代碼之前就能遇見哪些功能是重復的,不需實現之后再將相同代碼分離重構。
logger.debug("用and連接該謂語"); this.andPredicate(districtPredicate);CriteriaQuery
如果我們只是單純的查詢的話,沒有什么特殊要求的話,那我們直接就可以把我們的謂語返回。
return this.predicate;
沒錯,直接將謂語返回,debug的時候發現實際查詢時會獲取我們的謂語,并執行query.where語句。
如果需要復雜功能的話,可以使用CriteriaQuery。
// 把Predicate應用到CriteriaQuery中去,可以實現更豐富的查詢功能,可以分組,排序等 criteriaQuery.where(this.predicate); return criteriaQuery.getRestriction();查詢
基礎工作完成了,我們終于可以使用我們的謂語進行查詢啦。
/** * 查詢符合條件的考評員信息 * @param district 區域 * @param department 部門 * @param discipline 學科類別 * @return 符合條件的考評員信息 */ @Override public ListgetAllExaminerInfo(District district, Department department, Discipline discipline) { logger.debug("新建Map并設置屬性"); Map map = new HashMap<>(); map.put("department", department); map.put("district", district); map.put("discipline", discipline); logger.debug("調用根據Map的查詢方法"); return this.getExaminerInfoByMap(map); } /** * 根據Map查詢考評員的信息 * @param map 考評員查詢Map * @return 考評員列表 */ private List getExaminerInfoByMap(Map map) { logger.debug("獲取當前登錄用戶"); User currentLoginUser = userService.getCurrentLoginUser(); logger.debug("獲取查詢謂語"); Specification specification = ExaminerSpecs.base(currentLoginUser.getDepartment(), map); logger.debug("查詢并返回"); return (List ) examinerRepository.findAll(specification); }
怎么樣,謂語拼接完之后是不是很簡單呢?
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69615.html
摘要:以前都是用進行數據庫的開發,最近學習之后發現顯得更友好,所以我們就一起來了解一下的原理吧。簡單介紹持久性是的一個規范。它用于在對象和關系數據庫之間保存數據。充當面向對象的領域模型和關系數據庫系統之間的橋梁。是標識出主鍵是指定主鍵的自增方式。 以前都是用Mybatis進行數據庫的開發,最近學習Spring Boot之后發現JPA顯得更友好,所以我們就一起來了解一下JPA的原理吧。 Spr...
摘要:與的關系是什么是官方提出的持久化規范。它為開發人員提供了一種對象關聯映射工具來管理應用中的關系數據。他的出現主要是為了簡化現有的持久化開發工作和整合技術,結束現在,,等框架各自為營的局面。定義了在對數據庫中的對象處理查詢和事務運行時的的。 導讀: 在上篇文章中對Spring MVC常用的一些注解做了簡要的說明,在這篇文章中主要對Spring Data JPA 做一個簡要的說明,并附有一...
摘要:要是緊急排查個問題,媽蛋雖然有很多好處,比如和底層的無關。你的公司如果有,是不允許你亂用的。 知乎看到問題《SpringBoot開發使用Mybatis還是Spring Data JPA??》,順手一答,討論激烈。我實在搞不懂spring data jpa為啥選了hibernate作為它的實現,是Gavin King的裙帶關系么?DAO層搞來搞去,從jdbc到hibernate,從top...
摘要:忽略該字段的映射省略創建數據訪問層接口,需要繼承,第一個泛型參數是實體對象的名稱,第二個是主鍵類型。 SpringBoot 是為了簡化 Spring 應用的創建、運行、調試、部署等一系列問題而誕生的產物,自動裝配的特性讓我們可以更好的關注業務本身而不是外部的XML配置,我們只需遵循規范,引入相關的依賴就可以輕易的搭建出一個 WEB 工程 上一篇介紹了Spring JdbcTempl...
閱讀 2900·2021-11-23 09:51
閱讀 1547·2021-11-15 11:36
閱讀 3006·2021-10-13 09:40
閱讀 1863·2021-09-28 09:35
閱讀 13039·2021-09-22 15:00
閱讀 1367·2019-08-29 13:56
閱讀 2923·2019-08-29 13:04
閱讀 2697·2019-08-28 18:06