ABP開發框架先後端開發系列---(13)高級查詢功能及界面的處理

在通常的檢索界面中,基於界面易用和美觀方便的考慮,咱們每每只提供一些經常使用的條件查詢進行列表數據的查詢,可是有時候一些業務表字段不少,一些不常見的條件可能在某些場景下也須要用到。所以咱們在通用的查詢條件以外,通常能夠考慮增長 一個高級查詢的模塊來管理這些不常見條件的查詢處理。本篇隨筆基於這個需求,綜合ABP框架的特色,整合了高級查詢模塊功能的處理。html

一、高級查詢模塊的回顧

咱們知道,在界面佈局中,通常常見的查詢條件不能太多,不然會顯得臃腫並且佔用太多空間,很是不美觀,所以常見的查詢都是提供寥寥幾個的輸出條件進行列表記錄的查詢的。框架

又或者一些更多內容的界面,咱們也是僅僅提供多幾個條件,其餘的想辦法經過高級查詢界面進行查詢管理。async

在早期博客裏面《Winform開發框架之通用高級查詢模塊》,我曾經介紹過一款通用的高級查詢界面處理,用在Winform框架裏面,能夠對數據表更多的字段進行統一的查詢處理。ide

對於內容較多的查詢,咱們能夠在主界面增長一個高級查詢按鈕入口,如上圖所示,單擊後,顯示一個全部字段的列表,以下界面。函數

通常來講,查詢條件分爲文本輸入,如姓名,郵件,名稱等這些。佈局

日期類型條件輸入界面:post

數字類型條件輸入界面:this

 輸入以上幾種條件後,高級查詢界面裏面會顯示友好的條件內容,確保用戶可以看懂輸入的條件,以下所示是輸入幾個不一樣類型的條件的顯示內容。url

以上是高級查詢模塊的思路,總體界面和處理邏輯雖然能夠採用,可是在ABP框架模式下,之前的處理方式有所不一樣了,下面詳細介紹一下如何在ABP框架模塊下整合這個高級查詢模塊的內容。spa

 

二、ABP框架模塊下的高級查詢處理

咱們先來了解一下最終在ABP框架下整合的高級查詢模塊界面以下所示。

能夠設置一些模糊查詢條件,以及一些區間的查詢值,以下所示。

這個模塊是以ABP框架的Web API獲取數據,並經過Winform界面進行調用,從而造成了一個ABP+Winform的框架體系。

前面ABP框架系列介紹過,咱們通常使用GetAll和分頁條件DTO進行數據的檢索,以下是產品分頁DTO的定義

    /// <summary>
    /// 用於根據條件分頁查詢,DTO對象
    /// </summary>
    public class ProductPagedDto : PagedAndSortedInputDto

而PagedAndSortedInputDto也是自定義的類,它主要用來承載一些分頁和排序的信息,以下所示

    /// <summary>
    /// 帶有排序對象的分頁基類
    /// </summary>
    public class PagedAndSortedInputDto : PagedInputDto, ISortedResultRequest
    {
        /// <summary>
        /// 排序信息
        /// </summary>
        public string Sorting { get; set; }

其中的PagedInputDto也是自定義類,主要承載分頁信息。

    /// <summary>
    /// 分頁對象
    /// </summary>
    public class PagedInputDto : IPagedResultRequest
    {
        [Range(1, int.MaxValue)]
        public int MaxResultCount { get; set; }

        [Range(0, int.MaxValue)]
        public int SkipCount { get; set; }

        public PagedInputDto()
        {
            MaxResultCount = int.MaxValue;
        }
    }

這樣的構建,咱們能夠傳遞分頁和排序信息,所以在GetAll函數裏面,就能夠根據這些條件進行數據查詢了。

而咱們經過重寫過濾條件和排序處理,就能夠實現數據的分頁查詢了。對於產品信息的過濾處理和排序處理,咱們重寫函數以下所示。

        /// <summary>
        /// 自定義條件處理
        /// </summary>
        /// <param name="input">查詢條件Dto</param>
        /// <returns></returns>
        protected override IQueryable<Product> CreateFilteredQuery(ProductPagedDto input)
        {
            return base.CreateFilteredQuery(input)
                .WhereIf(!input.ExcludeId.IsNullOrWhiteSpace(), t => t.Id != input.ExcludeId) //不包含排除ID

                .WhereIf(!input.ProductNo.IsNullOrWhiteSpace(), t => t.ProductNo.Contains(input.ProductNo)) //如須要精確匹配則用Equals
                .WhereIf(!input.BarCode.IsNullOrWhiteSpace(), t => t.BarCode.Contains(input.BarCode)) //如須要精確匹配則用Equals
                .WhereIf(!input.MaterialCode.IsNullOrWhiteSpace(), t => t.MaterialCode.Contains(input.MaterialCode)) //如須要精確匹配則用Equals
                .WhereIf(!input.ProductType.IsNullOrWhiteSpace(), t => t.ProductType.Contains(input.ProductType)) //如須要精確匹配則用Equals
                .WhereIf(!input.ProductName.IsNullOrWhiteSpace(), t => t.ProductName.Contains(input.ProductName)) //如須要精確匹配則用Equals
                .WhereIf(!input.Unit.IsNullOrWhiteSpace(), t => t.Unit.Contains(input.Unit)) //如須要精確匹配則用Equals
                .WhereIf(!input.Note.IsNullOrWhiteSpace(), t => t.Note.Contains(input.Note)) //如須要精確匹配則用Equals
                .WhereIf(!input.Description.IsNullOrWhiteSpace(), t => t.Description.Contains(input.Description)) //如須要精確匹配則用Equals
                 
                 //狀態
                .WhereIf(input.Status.HasValue, t => t.Status==input.Status)
                                                                                              
                 //成本價區間查詢
                .WhereIf(input.PriceStart.HasValue, s => s.Price >= input.PriceStart.Value)
                .WhereIf(input.PriceEnd.HasValue, s => s.Price <= input.PriceEnd.Value)

                //銷售價區間查詢
                .WhereIf(input.SalePriceStart.HasValue, s => s.SalePrice >= input.SalePriceStart.Value)
                .WhereIf(input.SalePriceEnd.HasValue, s => s.SalePrice <= input.SalePriceEnd.Value)

                //特價區間查詢
                .WhereIf(input.SpecialPriceStart.HasValue, s => s.SpecialPrice >= input.SpecialPriceStart.Value)
                .WhereIf(input.SpecialPriceEnd.HasValue, s => s.SpecialPrice <= input.SpecialPriceEnd.Value)
                .WhereIf(input.IsUseSpecial.HasValue, t => t.IsUseSpecial == input.IsUseSpecial) //如須要精確匹配則用Equals
                                                                                                  
                //最低折扣區間查詢
                .WhereIf(input.LowestDiscountStart.HasValue, s => s.LowestDiscount >= input.LowestDiscountStart.Value)
                .WhereIf(input.LowestDiscountEnd.HasValue, s => s.LowestDiscount <= input.LowestDiscountEnd.Value)

                //建立日期區間查詢
                .WhereIf(input.CreationTimeStart.HasValue, s => s.CreationTime >= input.CreationTimeStart.Value)
                .WhereIf(input.CreationTimeEnd.HasValue, s => s.CreationTime <= input.CreationTimeEnd.Value);
        }

        /// <summary>
        /// 自定義排序處理
        /// </summary>
        /// <param name="query">可查詢LINQ</param>
        /// <param name="input">查詢條件Dto</param>
        /// <returns></returns>
        protected override IQueryable<Product> ApplySorting(IQueryable<Product> query, ProductPagedDto input)
        {
            //按建立時間倒序排序
            return base.ApplySorting(query, input).OrderByDescending(s => s.CreationTime);//時間降序
        }

雖然咱們通常在界面上不會放置全部的條件,可是高級查詢模塊卻是能夠把分頁條件DTO裏面的條件所有擺上去的。

高級查詢模塊的條件以下所示。

 咱們高級查詢裏面的條件仍是以GetAll裏面的對象分頁查詢Dto裏面的屬性,咱們須要根據這些條件進行構建,也須要以這些屬性的類型進行一個控件的選擇。

所以咱們須要一個屬性的名稱說明,以及在高級查詢模塊的列表界面中對顯示那些字段進行控制,以下代碼所示。

        private FrmAdvanceSearch dlg;
        /// <summary>
        /// 高級查詢的操做
        /// </summary>        
        private async void AdvanceSearch()
        {
            if (dlg == null)
            {
                dlg = new FrmAdvanceSearch();
                dlg.SetFieldTypeList<ProductPagedDto>();//經過分頁對象獲取查詢屬性和類型 
                dlg.ColumnNameAlias = await ProductApiCaller.Instance.GetColumnNameAlias();                
                dlg.DisplayColumns = "ProductNo,BarCode,MaterialCode,ProductType,ProductName,Unit,Price,SalePrice,SpecialPrice,IsUseSpecial,LowestDiscount,Note,Description,Status,CreatorUserId,CreationTime";

經過 SetFieldTypeList<ProductPagedDto> 的處理,咱們把分頁對象的查詢屬性和類型賦值給了高級查詢模塊,讓它根據類型來建立不一樣的輸入顯示,如常規的字符串、數值區段、日期區段,下拉列表等等。

對於下拉列表,咱們須要綁定它的數據源,以下代碼所示。

 dlg.AddColumnListItem("ProductType", await DictItemUtil.GetDictListItemByDictType("產品類型"));//字典列表
 dlg.AddColumnListItem("Status", await DictItemUtil.GetDictListItemByDictType("產品狀態"));//字典列表

而對於一些常規的固定列表,也能夠以相似的方式加入下拉列表

    //固定轉義的列表
    var specialList = new List<CListItem>() { new CListItem("特價", "True"), new CListItem("通常", "False") };
    dlg.AddColumnListItem("IsUseSpecial", specialList);

或者

    dlg.AddColumnListItem("Sex", "男,女");//固定列表

所以整個調用高級查詢模塊的代碼以下所示

    private FrmAdvanceSearch dlg;
    /// <summary>
    /// 高級查詢的操做
    /// </summary>        
    private async void AdvanceSearch()
    {
        if (dlg == null)
        {
            dlg = new FrmAdvanceSearch();
            dlg.SetFieldTypeList<ProductPagedDto>();//經過分頁對象獲取查詢屬性和類型 
            dlg.ColumnNameAlias = await ProductApiCaller.Instance.GetColumnNameAlias();                
            dlg.DisplayColumns = "ProductNo,BarCode,MaterialCode,ProductType,ProductName,Unit,Price,SalePrice,SpecialPrice,IsUseSpecial,LowestDiscount,Note,Description,Status,CreatorUserId,CreationTime";

            #region 下拉列表數據

            dlg.AddColumnListItem("ProductType", await DictItemUtil.GetDictListItemByDictType("產品類型"));//字典列表
            dlg.AddColumnListItem("Status", await DictItemUtil.GetDictListItemByDictType("產品狀態"));//字典列表

            //固定轉義的列表
            var specialList = new List<CListItem>() { new CListItem("特價", "True"), new CListItem("通常", "False") };
            dlg.AddColumnListItem("IsUseSpecial", specialList);

            //dlg.AddColumnListItem("Sex", "男,女");//固定列表
            //dlg.AddColumnListItem("Credit", await ProductApiCaller.Instance.GetFieldList("Credit"));//動態列表

            #endregion

            dlg.ConditionChanged += new FrmAdvanceSearch.ConditionChangedEventHandler(dlg_ConditionChanged);
        }
        dlg.ShowDialog();
    }

在處理獲取數據GetData函數的時候,咱們須要根據高級查詢進行必定的切換,以便顯示正確的過濾條件,以下代碼所示是獲取數據的處理。

        /// <summary>
        /// 獲取數據
        /// </summary>
        /// <returns></returns>
        private async Task<IPagedResult<ProductDto>> GetData()
        {
            ProductPagedDto pagerDto = null;
            if (advanceCondition != null)
            {
                pagerDto = new ProductPagedDto(this.winGridViewPager1.PagerInfo);
                pagerDto = dlg.GetPagedResult(pagerDto);               
            }
            else
            {
                //構建分頁的條件和查詢條件
                pagerDto = new ProductPagedDto(this.winGridViewPager1.PagerInfo)
                {
                    //添加所需條件
                    ProductNo = this.txtProductNo.Text.Trim(),
                    BarCode = this.txtBarCode.Text.Trim(),
                    MaterialCode = this.txtMaterialCode.Text.Trim(),
                    ProductType = this.txtProductType.Text.Trim(),
                    ProductName = this.txtProductName.Text.Trim(),
                    Description = this.txtDescription.Text.Trim(),
                };

                //日期和數值範圍定義
                //建立時間,需在ProductPagedDto中添加DateTime?類型字段CreationTimeStart和CreationTimeEnd
                var CreationTime = new TimeRange(this.txtCreationTime1.Text, this.txtCreationTime2.Text); //日期類型
                pagerDto.CreationTimeStart = CreationTime.Start;
                pagerDto.CreationTimeEnd = CreationTime.End;

            }

            var result = await ProductApiCaller.Instance.GetAll(pagerDto);
            return result;
        }

在高級查詢的處理方式下,咱們是傳入一個列表的分頁對象屬性,而後傳入一個分頁DTO對象,就能夠構建出咱們須要的分頁查詢條件,傳遞給Web API端獲取對應條件的數據了。

    pagerDto = new ProductPagedDto(this.winGridViewPager1.PagerInfo);
    pagerDto = dlg.GetPagedResult(pagerDto);        

而高級查詢模塊,所須要處理的邏輯就是須要根據不一樣的屬性類型,賦值常規的屬性值或者區段屬性值,從而構建出分頁對應的屬性條件便可。

若是是區段(包括日期或者數值)的,咱們分頁查詢條件裏面,會有一個ABCStart,ABCEnd的對象屬性,依照這個規則,獲取到對應的用戶輸入,採用反射方式賦值DTO對象便可。

相關文章
相關標籤/搜索