成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Spring Data JPA 查詢

icattlecoder / 2957人閱讀

摘要:根據(jù)區(qū)域部門學(xué)科類別查詢出符合條件的考評(píng)人員。繼承接口我們的考評(píng)員倉庫原繼承,為了實(shí)現(xiàn)可以復(fù)雜查詢,繼承接口。實(shí)現(xiàn)規(guī)格接口為了規(guī)范,我們建了一個(gè)的查詢規(guī)格的包,將所有生成查詢規(guī)格的類放入該包中。

SpringData

Spring項(xiàng)目中,我們使用JPA進(jìn)行查詢,只需簡(jiǎn)單地繼承SpringData提供的接口即可實(shí)現(xiàn)強(qiáng)大的數(shù)據(jù)查詢功能。

之前的強(qiáng)檢器具統(tǒng)計(jì)管理用的僅僅是單表查詢,理解不深,這次開發(fā)的考評(píng)員綜合查詢涉及到了多個(gè)實(shí)體間的查詢,值得學(xué)習(xí),特此記錄。

以下是ER圖。

管理部門選擇本部門或其管轄的部門中的某人員作為該部門的考評(píng)人員。根據(jù)區(qū)域、部門、學(xué)科類別查詢出符合條件的考評(píng)人員。

概述

復(fù)雜查詢,我們就需要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);
}

該接口中聲明的方法都有一個(gè)共同的參數(shù):Specification,翻譯過來就是規(guī)范的意思。

這是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接口中有一個(gè)toPredicate方法,看不懂代碼我們可以看注釋。

Creates a WHERE clause for a query of the referenced entity in form of a {Predicate}

用謂詞的形式為引用的實(shí)體創(chuàng)建一個(gè)WHERE語句。

到這里,我們應(yīng)該明白了這個(gè)查詢的原理:我們先生成我們需要的謂語,然后用toPredicate將謂語生成為where語句,最后再使用我們Specification類型的where語句作為參數(shù)用JpaSpecificationExecutor接口中定義的方法進(jìn)行查詢。

繼承JpaSpecificationExecutor接口
public interface ExaminerRepository extends CrudRepository, JpaSpecificationExecutor {
}

我們的考評(píng)員倉庫原繼承CrudRepository,為了實(shí)現(xiàn)可以復(fù)雜查詢,繼承JpaSpecificationExecutor接口。

實(shí)現(xiàn)規(guī)格接口

為了規(guī)范,我們建了一個(gè)spec的查詢規(guī)格的包,將所有生成查詢規(guī)格的類放入該包中。

/**
 * @author zhangxishuo on 2018/5/26
 * 考評(píng)人員查詢規(guī)格
 */

public class ExaminerSpecs {

    // 日志
    private static final Logger logger = Logger.getLogger(ExaminerSpecs.class);

    public static Specification base(Department userDepartment, final Map map) {
        return new Specification() {

            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                return null;
            }
        };
    }
}

我們?cè)谶@個(gè)類中寫了一個(gè)base方法,用于根據(jù)傳入的參數(shù)生成一個(gè)查詢規(guī)格。

return語句中,我們new了一個(gè)接口,然后在new這個(gè)接口的同時(shí)對(duì)這個(gè)接口進(jìn)行實(shí)現(xiàn),實(shí)現(xiàn)接口中的toPredicate方法。

toPredicate中的三個(gè)參數(shù)意義。Root:查詢的模型;CriteriaQuery:標(biāo)準(zhǔn)查詢,用于查詢的;CriteriaBuilder:標(biāo)準(zhǔn)構(gòu)建,用戶構(gòu)建查詢語句的。

大家不要去糾結(jié)是直接new接口然后在花括號(hào)中實(shí)現(xiàn)還是寫一個(gè)類實(shí)現(xiàn)接口然后再去new?

這里說一下我自己的理解。其實(shí)這主要是看實(shí)際需要,如果這個(gè)接口的實(shí)現(xiàn)類需要被好多個(gè)其他類調(diào)用,為了代碼的復(fù)用,我們就會(huì)寫一個(gè)類去實(shí)現(xiàn)接口,就像我們后臺(tái)MVC架構(gòu)的業(yè)務(wù)邏輯層,因?yàn)橥粋€(gè)方法可能會(huì)被好多個(gè)控制器進(jìn)行調(diào)用,所以我們建一個(gè)Service接口,再建立一個(gè)Service接口實(shí)現(xiàn)類,然后其他類需要時(shí)進(jìn)行Autowire。

如果我們的方法不需要復(fù)用,那Android代碼就是我們最好的例子(Android中大量使用了new接口然后在new時(shí)去實(shí)現(xiàn)的寫法)。

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官方文檔中對(duì)按鈕添加點(diǎn)擊事件的示例代碼,我們看到這里的View.OnClickListener()就是在new的時(shí)候再去實(shí)現(xiàn)的。其實(shí)這也不難理解,打開我們每天用的APP,幾乎每個(gè)按鈕,每個(gè)視圖的功能都是不一樣的,所以不需要進(jìn)行代碼復(fù)用。

構(gòu)建謂語

謂語是什么呢?按我的理解,一個(gè)謂語就是一個(gè)條件。

logger.debug("構(gòu)建謂語,人員的部門的區(qū)域的id等于map中區(qū)域的id");
Predicate districtPredicate = criteriaBuilder
        .equal(root.join("qualifier")
                    .join("department")
                    .join("district")
                    .get("id")
                    .as(Long.class),
                ((District) map.get("district"))
                    .getId());

我們使用criteriaBuilderequal方法構(gòu)建了一個(gè)等于的條件(或謂語),該條件要求考評(píng)員(root)的人員的部門的區(qū)域的id轉(zhuǎn)化為Long類型的結(jié)果與傳入的區(qū)域的id相等。

類似的寫法,我們可以構(gòu)建出部門和學(xué)科的謂語。

連接謂語

謂語創(chuàng)建完了,我們還需要將這些謂語進(jìn)行連接。

這里我們需要用到and條件,即區(qū)域符合且部門符合且學(xué)科類別符合。

為了方便構(gòu)建,這里參考之前的項(xiàng)目代碼構(gòu)建了一個(gè)用and拼接謂語的方法。

private Predicate predicate = null;
private CriteriaBuilder criteriaBuilder;

// 設(shè)置and謂語.注意,這里只能設(shè)置and關(guān)系的謂語,如果謂語為OR,則需要手動(dòng)設(shè)置
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);
        }
    }
}

這幾行代碼就體現(xiàn)了一名優(yōu)秀軟件工程師的素養(yǎng),優(yōu)秀的人在寫代碼之前就能遇見哪些功能是重復(fù)的,不需實(shí)現(xiàn)之后再將相同代碼分離重構(gòu)。

logger.debug("用and連接該謂語");
this.andPredicate(districtPredicate);
CriteriaQuery

如果我們只是單純的查詢的話,沒有什么特殊要求的話,那我們直接就可以把我們的謂語返回。

return this.predicate;

沒錯(cuò),直接將謂語返回,debug的時(shí)候發(fā)現(xiàn)實(shí)際查詢時(shí)會(huì)獲取我們的謂語,并執(zhí)行query.where語句。

如果需要復(fù)雜功能的話,可以使用CriteriaQuery。

// 把Predicate應(yīng)用到CriteriaQuery中去,可以實(shí)現(xiàn)更豐富的查詢功能,可以分組,排序等
criteriaQuery.where(this.predicate);

return criteriaQuery.getRestriction();
查詢

基礎(chǔ)工作完成了,我們終于可以使用我們的謂語進(jìn)行查詢啦。

/**
 * 查詢符合條件的考評(píng)員信息
 * @param district   區(qū)域
 * @param department 部門
 * @param discipline 學(xué)科類別
 * @return 符合條件的考評(píng)員信息
 */
@Override
public List getAllExaminerInfo(District district, Department department, Discipline discipline) {
    logger.debug("新建Map并設(shè)置屬性");
    Map map = new HashMap<>();
    map.put("department", department);
    map.put("district", district);
    map.put("discipline", discipline);

    logger.debug("調(diào)用根據(jù)Map的查詢方法");
    return this.getExaminerInfoByMap(map);
}

/**
 * 根據(jù)Map查詢考評(píng)員的信息
 * @param map 考評(píng)員查詢Map
 * @return 考評(píng)員列表
 */
private List getExaminerInfoByMap(Map map) {
    logger.debug("獲取當(dāng)前登錄用戶");
    User currentLoginUser = userService.getCurrentLoginUser();

    logger.debug("獲取查詢謂語");
    Specification specification = ExaminerSpecs.base(currentLoginUser.getDepartment(), map);

    logger.debug("查詢并返回");
    return (List) examinerRepository.findAll(specification);
}

怎么樣,謂語拼接完之后是不是很簡(jiǎn)單呢?

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69615.html

相關(guān)文章

  • Spring Boot 的簡(jiǎn)單教程(四)數(shù)據(jù)庫連接之Spring Data JPA的使用

    摘要:以前都是用進(jìn)行數(shù)據(jù)庫的開發(fā),最近學(xué)習(xí)之后發(fā)現(xiàn)顯得更友好,所以我們就一起來了解一下的原理吧。簡(jiǎn)單介紹持久性是的一個(gè)規(guī)范。它用于在對(duì)象和關(guān)系數(shù)據(jù)庫之間保存數(shù)據(jù)。充當(dāng)面向?qū)ο蟮念I(lǐng)域模型和關(guān)系數(shù)據(jù)庫系統(tǒng)之間的橋梁。是標(biāo)識(shí)出主鍵是指定主鍵的自增方式。 以前都是用Mybatis進(jìn)行數(shù)據(jù)庫的開發(fā),最近學(xué)習(xí)Spring Boot之后發(fā)現(xiàn)JPA顯得更友好,所以我們就一起來了解一下JPA的原理吧。 Spr...

    yuxue 評(píng)論0 收藏0
  • Spring Boot [組件學(xué)習(xí)-Spring Data JPA]

    摘要:與的關(guān)系是什么是官方提出的持久化規(guī)范。它為開發(fā)人員提供了一種對(duì)象關(guān)聯(lián)映射工具來管理應(yīng)用中的關(guān)系數(shù)據(jù)。他的出現(xiàn)主要是為了簡(jiǎn)化現(xiàn)有的持久化開發(fā)工作和整合技術(shù),結(jié)束現(xiàn)在,,等框架各自為營的局面。定義了在對(duì)數(shù)據(jù)庫中的對(duì)象處理查詢和事務(wù)運(yùn)行時(shí)的的。 導(dǎo)讀: 在上篇文章中對(duì)Spring MVC常用的一些注解做了簡(jiǎn)要的說明,在這篇文章中主要對(duì)Spring Data JPA 做一個(gè)簡(jiǎn)要的說明,并附有一...

    andong777 評(píng)論0 收藏0
  • 我就是不看好jpa

    摘要:要是緊急排查個(gè)問題,媽蛋雖然有很多好處,比如和底層的無關(guān)。你的公司如果有,是不允許你亂用的。 知乎看到問題《SpringBoot開發(fā)使用Mybatis還是Spring Data JPA??》,順手一答,討論激烈。我實(shí)在搞不懂spring data jpa為啥選了hibernate作為它的實(shí)現(xiàn),是Gavin King的裙帶關(guān)系么?DAO層搞來搞去,從jdbc到hibernate,從top...

    NusterCache 評(píng)論0 收藏0
  • 一起來學(xué)SpringBoot | 第六篇:整合SpringDataJpa

    摘要:忽略該字段的映射省略創(chuàng)建數(shù)據(jù)訪問層接口,需要繼承,第一個(gè)泛型參數(shù)是實(shí)體對(duì)象的名稱,第二個(gè)是主鍵類型。 SpringBoot 是為了簡(jiǎn)化 Spring 應(yīng)用的創(chuàng)建、運(yùn)行、調(diào)試、部署等一系列問題而誕生的產(chǎn)物,自動(dòng)裝配的特性讓我們可以更好的關(guān)注業(yè)務(wù)本身而不是外部的XML配置,我們只需遵循規(guī)范,引入相關(guān)的依賴就可以輕易的搭建出一個(gè) WEB 工程 上一篇介紹了Spring JdbcTempl...

    Dionysus_go 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<