中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Jpa?Specification怎么實現and和or同時使用查詢

發布時間:2021-11-23 11:07:30 來源:億速云 閱讀:174 作者:小新 欄目:開發技術

這篇文章主要為大家展示了“Jpa Specification怎么實現and和or同時使用查詢”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“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 動態查詢之AND、OR結合使用

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

問題描述

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

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的動態查詢,這里我們使用的方式是:實現 Specification 接口,自定義動態查詢邏輯。這也是我個人比較推薦的方式。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);
}

下面是前端傳過來的動態查詢的參數對象:

@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]));
    };
}

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

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

就這樣,我們就執行了一次動態查詢,并獲取到了結果。

上面的動態查詢,實際上等價于下面的偽代碼:

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 Specification怎么實現and和or同時使用查詢”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

封丘县| 东乌珠穆沁旗| 邹平县| 古浪县| 昂仁县| 凤山县| 桂林市| 上犹县| 嘉义县| 永福县| 阿克苏市| 金塔县| 宜阳县| 道真| 星子县| 新龙县| 明水县| 应城市| 吐鲁番市| 原阳县| 安仁县| 安宁市| 元阳县| 云龙县| 东兰县| 亳州市| 彭泽县| 崇文区| 通渭县| 恩平市| 山西省| 吐鲁番市| 遂宁市| 大丰市| 湾仔区| 道孚县| 灌云县| 什邡市| 淮北市| 晴隆县| 沁水县|