欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Jpa?Specification如何實現and和or同時使用查詢

 更新時間:2021年11月23日 09:41:31   作者:qq_41315539  
這篇文章主要介紹了Jpa?Specification如何實現and和or同時使用查詢,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

同時使用and和or的查詢

UserServiceImpl 類,service實現類

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
 
@Service
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private RongUserRepository rongUserRepository;
     //FriendNumResult  自定的返回類型
    //FriendNumParam  自定義的封裝參數的類型
    //RongUser  實體類型
    @Override
    public FriendNumResult friendNum(FriendNumParam friendNumParam) {
        FriendNumResult friendNumResult=new FriendNumResult();
 
        Specification<RongUser> specification = new Specification<RongUser>(){
 
            @Override
            public Predicate toPredicate(Root<RongUser> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //封裝and語句
                List<Predicate> listAnd = new ArrayList<Predicate>();
                //這里是hql,所以root.get(),方法里面必須是對應的實體屬性
                listAnd.add(criteriaBuilder.equal(root.get("perLevel").as(Integer.class), friendNumParam.getPerLevel()));
                Predicate[] array_and=new Predicate[listAnd.size()];
                Predicate Pre_And = criteriaBuilder.and(listAnd.toArray(array_and));
 
                //封裝or語句
                List<Predicate> listOr = new ArrayList<Predicate>();
                listOr.add(criteriaBuilder.equal(root.get("fId").as(Integer.class), friendNumParam.getUid()));
                listOr.add(criteriaBuilder.equal(root.get("fId2").as(Integer.class), friendNumParam.getUid()));
                Predicate[] arrayOr = new Predicate[listOr.size()];
                Predicate Pre_Or = criteriaBuilder.or(listOr.toArray(arrayOr));
 
                return criteriaQuery.where(Pre_And,Pre_Or).getRestriction();
                //單獨使用  and 或者  or 時 返回
                //return criteriaBuilder.and(list.toArray());
            }
        };
        long num=this.rongUserRepository.count(specification);
        friendNumResult.setFriendNum(Integer.valueOf((int)num));
        return friendNumResult;
    }
}

RongUserRepository接口

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
//RongUser  自己的實體類型
public interface RongUserRepository extends JpaRepository<RongUser,Integer> , JpaSpecificationExecutor<RongUser> {
}

注意:使用Specification之前,RongUserRepository接口必須實現JpaSpecificationExecutor<RongUser>,RongUser對應表的實體類

JPA 動態(tài)查詢之AND、OR結合使用

現在,我負責開發(fā)的項目中,使用JPA作為ORM框架。有了JPA,一行SQL都沒寫過。在昨天,有一個新的需求,需要進行動態(tài)查詢,這個簡單。但是有一個地方需要AND、OR結合使用,這里,我將記錄下我的理解與寫法,希望能幫助到大家。

問題描述

需要根據條件進行動態(tài)查詢,實現一條類似下文的語句:

SELECT *
FROM   table
WHERE  1 = 1
   if (a == 1)
        AND table.column1 = a
   if (b != null)
        AND table.column2 = b
   if (cList != null && cList.size() > 0)
        AND table.column3 IN cList
   if (d == 2 || dd == 2)
        AND (table.column4 = d OR table.column5 = dd)

上面是幾行偽代碼。意思是,幾個條件之間是AND連接,但是其中的部分條件,是使用OR連接的。

在我們的實際項目中,這個場景也是很常見的。這里,我將分享下具體的寫法。以我們項目中的例子為例。

代碼示例

JPA的動態(tài)查詢,這里我們使用的方式是:實現 Specification 接口,自定義動態(tài)查詢邏輯。這也是我個人比較推薦的方式。JPA的使用、Specification 接口基礎知識這里我就不講了。有興趣的朋友可以查閱官方文檔學習。

下面,我們首先定義好我們的數據庫實體:

@Data
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    /**
     * 用戶名
     */
    private String username;
    /**
     * 年齡
     */
    private Integer age;
    /**
     * 生日
     */
    private Date birthDay;
    /**
     * 刪除標識; 0 - 未刪除,1 - 已刪除
     */
    private Integer deleteFlag;
}

然后定義好DAO層接口:

@Repository
public interface UserDAO extends JpaRepository<User, Long> {
    /**
     * 其實,這個功能一般用作 list 接口使用,一般結合分頁查詢使用。這里,我不做介紹,看情況要不要后期加上教程
     */
    List<User> findAll(Specification<User> querySpec);
}

下面是前端傳過來的動態(tài)查詢的參數對象:

@Data
public class UserDTO {
    /**
     * 用戶名,用于模糊搜索
     */
    private String username;
    /**
     * 用戶ID,用于 In 查詢
     */
    private List<String> userIdList;
    /**
     * 用戶年齡,用于 OR In 查詢
     */
    private List<Integer> ageList;
    /**
     * 生日,開始
     */
    @JsonFormat(pattern = "yyyy-MM-dd", locale = "zh", timezone = "GMT+8")
    private Date birthDayBegin;
    /**
     * 生日,結束
     */
    @JsonFormat(pattern = "yyyy-MM-dd", locale = "zh", timezone = "GMT+8")
    private Date birthDayEnd;
}

然后,重要的地方來了,我們實現 Specification 接口,定義查詢邏輯:

在實際代碼操作中,我會將這部分邏輯抽離為一個單獨的方法,使用lambda表達式完成,其實也就是匿名內部類。

private Specification<User> getListSpec(UserDTO userDTO) {
    return (root, criteriaQuery, criteriaBuilder) -> {
        List<Predicate> predicateList = new ArrayList<>();
        // 未刪除標識,只查詢未刪除的數據
        predicateList.add(criteriaBuilder.equal(root.get("deleteFlag"), 0));
        // 根據 用戶名 或 年齡List 查詢
        List<Predicate> usernameOrAgePredicate = new ArrayList<>();
        String username = userDTO.getUsername();
        if (!StringUtils.isEmpty(username)) {
            // 用戶名這里,用模糊匹配
            usernameOrAgePredicate.add(criteriaBuilder.like(root.get("username"), "%" + username + "%"));
        }
        List<Integer> ageList = userDTO.getAgeList();
        if (!CollectionUtils.isEmpty(ageList)) {
            // 下面是一個 IN查詢
            CriteriaBuilder.In<Integer> in = criteriaBuilder.in(root.get("age"));
            ageList.forEach(in::value);
            usernameOrAgePredicate.add(in);
        }
        /* 下面這一行代碼很重要。
         * criteriaBuilder.or(Predicate... restrictions) 接收多個Predicate,可變參數;
         * 這多個 Predicate條件之間,是使用OR連接的;該方法最終返回 一個Predicate對象;
         */
        predicateList.add(criteriaBuilder.or(usernameOrAgePredicate.toArray(new Predicate[0])));
        // 用戶ID List,IN 查詢
        List<Integer> userIdList = reqDTO.getUserIdList();
        if (!CollectionUtils.isEmpty(userIdList)) {
            CriteriaBuilder.In<Integer> in = criteriaBuilder.in(root.get("id"));
            userIdList.forEach(in::value);
            predicateList.add(in);
        }
        // 生日時間段查詢
        Date birthDayBegin = reqDTO.getBirthDayBegin();
        Date birthDayEnd = reqDTO.getBirthDayEnd();
        if (birthDayBegin != null && birthDayEnd != null) {
            // DateUtils 是我自定義的一個工具類
            Date begin = DateUtils.startOfDay(birthDayBegin);
            Date end = DateUtils.endOfDay(birthDayEnd);
            predicateList.add(criteriaBuilder.greaterThanOrEqualTo(root.get("birthDay"), begin));
            predicateList.add(criteriaBuilder.lessThanOrEqualTo(root.get("birthDay"), end));
        }
        // 最終,使用AND 連接 多個 Predicate 查詢條件
        return criteriaBuilder.and(predicateList.toArray(new Predicate[0]));
    };
}

這樣,我們的動態(tài)查詢部分就構建完畢了。具體怎么使用呢?如下:

Specification<User> querySpec = this.getListSpec(userDTO);
List<User> userList = userDAO.findAll(querySpec);

就這樣,我們就執(zhí)行了一次動態(tài)查詢,并獲取到了結果。

上面的動態(tài)查詢,實際上等價于下面的偽代碼:

SELECT * 
FROM   user 
WHERE  user.deleteFlag = 0 
AND    ( user.username like '%{username}%' OR user.age IN ageList )
AND    user.id IN userIdList
AND    user.birthDay > birthDayBegin AND user.birthDay < birthDayEnd ;

當前,需要對應值不為空,才會拼接相應的AND條件。

至此,JPA 動態(tài)查詢之 AND OR結合使用,教程到這里就結束了。以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Zookeeper全局唯一ID生成方案解析

    Zookeeper全局唯一ID生成方案解析

    這篇文章主要介紹了Zookeeper全局唯一ID生成方案解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-12-12
  • Java中輸出字符的ASCII值實例

    Java中輸出字符的ASCII值實例

    這篇文章主要介紹了Java中輸出字符的ASCII值實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Java神操作:圖片快速轉換PDF秘籍

    Java神操作:圖片快速轉換PDF秘籍

    想掌握Java神操作,將圖片快速轉換成PDF嗎?這份秘籍將一步步引導你,輕松實現這一目標,別等了,跟著我們一起,解鎖這項超實用技能吧!
    2024-02-02
  • Netty事件循環(huán)主邏輯NioEventLoop的run方法分析

    Netty事件循環(huán)主邏輯NioEventLoop的run方法分析

    這篇文章主要介紹了Netty事件循環(huán)主邏輯NioEventLoop的run方法分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-03-03
  • javaSE基礎如何通俗的理解javaBean是什么

    javaSE基礎如何通俗的理解javaBean是什么

    所謂的Java Bean,就是一個java類,編譯后成為了一個后綴名是 .class的文件。這就是Java Bean,很多初學者,包括當年的我自己,總是被這些專有名詞搞的暈頭轉向
    2021-10-10
  • 基于JPA的Repository使用詳解

    基于JPA的Repository使用詳解

    這篇文章主要介紹了JPA的Repository使用詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • mybatis-plus實體類主鍵策略有3種(小結)

    mybatis-plus實體類主鍵策略有3種(小結)

    這篇文章主要介紹了mybatis-plus實體類主鍵策略有3種(小結),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • 使用SpringAop動態(tài)獲取mapper執(zhí)行的SQL,并保存SQL到Log表中

    使用SpringAop動態(tài)獲取mapper執(zhí)行的SQL,并保存SQL到Log表中

    這篇文章主要介紹了使用SpringAop動態(tài)獲取mapper執(zhí)行的SQL,并保存SQL到Log表中問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 樹,二叉樹(完全二叉樹,滿二叉樹)概念圖解

    樹,二叉樹(完全二叉樹,滿二叉樹)概念圖解

    今天小編就為大家分享一篇關于二叉樹的圖文詳解,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧,希望能對你有所幫助
    2021-07-07
  • Java異步調用轉同步方法實例詳解

    Java異步調用轉同步方法實例詳解

    這篇文章主要介紹了Java異步調用轉同步方法實例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06

最新評論