在一般的檢索界面中助币,基于界面易用和美觀方便的考慮朦蕴,我們往往只提供一些常用的條件查詢進行列表數(shù)據(jù)的查詢疏尿,但是有時候一些業(yè)務(wù)表字段很多榆鼠,一些不常見的條件可能在某些場景下也需要用到。因此我們在通用的查詢條件之外俱笛,一般可以考慮增加 一個高級查詢的模塊來管理這些不常見條件的查詢處理捆姜。本篇隨筆基于這個需求,綜合ABP框架的特點迎膜,整合了高級查詢模塊功能的處理泥技。
1、高級查詢模塊的回顧
我們知道磕仅,在界面布局中珊豹,一般常見的查詢條件不能太多,否則會顯得臃腫而且占用太多空間宽涌,非常不美觀平夜,因此常見的查詢都是提供寥寥幾個的輸出條件進行列表記錄的查詢的。
又或者一些更多內(nèi)容的界面卸亮,我們也是僅僅提供多幾個條件忽妒,其他的想辦法通過高級查詢界面進行查詢管理。
在早期博客里面《Winform開發(fā)框架之通用高級查詢模塊》兼贸,我曾經(jīng)介紹過一款通用的高級查詢界面處理段直,用在Winform框架里面,可以對數(shù)據(jù)表更多的字段進行統(tǒng)一的查詢處理溶诞。
對于內(nèi)容較多的查詢鸯檬,我們可以在主界面增加一個高級查詢按鈕入口,如上圖所示螺垢,單擊后喧务,顯示一個所有字段的列表,如下界面枉圃。
一般來說功茴,查詢條件分為文本輸入,如姓名孽亲,郵件坎穿,名稱等這些。
日期類型條件輸入界面:
數(shù)字類型條件輸入界面:
輸入以上幾種條件后,高級查詢界面里面會顯示友好的條件內(nèi)容玲昧,確保用戶能夠看懂輸入的條件栖茉,如下所示是輸入幾個不同類型的條件的顯示內(nèi)容。
以上是高級查詢模塊的思路孵延,整體界面和處理邏輯雖然可以采用吕漂,但是在ABP框架模式下,以前的處理方式有所不同了隙袁,下面詳細介紹一下如何在ABP框架模塊下整合這個高級查詢模塊的內(nèi)容痰娱。
2弃榨、ABP框架模塊下的高級查詢處理
我們先來了解一下最終在ABP框架下整合的高級查詢模塊界面如下所示菩收。
可以設(shè)置一些模糊查詢條件,以及一些區(qū)間的查詢值鲸睛,如下所示娜饵。
這個模塊是以ABP框架的Web API獲取數(shù)據(jù),并通過Winform界面進行調(diào)用官辈,從而形成了一個ABP+Winform的框架體系箱舞。
前面ABP框架系列介紹過,我們一般使用GetAll和分頁條件DTO進行數(shù)據(jù)的檢索拳亿,如下是產(chǎn)品分頁DTO的定義
/// <summary>
/// 用于根據(jù)條件分頁查詢晴股,DTO對象
/// </summary>
public class ProductPagedDto : PagedAndSortedInputDto
而PagedAndSortedInputDto也是自定義的類,它主要用來承載一些分頁和排序的信息肺魁,如下所示
/// <summary>
/// 帶有排序?qū)ο蟮姆猪摶? /// </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;
}
}
這樣的構(gòu)建鹅经,我們可以傳遞分頁和排序信息寂呛,因此在GetAll函數(shù)里面,就可以根據(jù)這些條件進行數(shù)據(jù)查詢了瘾晃。
而我們通過重寫過濾條件和排序處理贷痪,就可以實現(xiàn)數(shù)據(jù)的分頁查詢了。對于產(chǎn)品信息的過濾處理和排序處理蹦误,我們重寫函數(shù)如下所示劫拢。
/// <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
//狀態(tài)
.WhereIf(input.Status.HasValue, t => t.Status==input.Status)
//成本價區(qū)間查詢
.WhereIf(input.PriceStart.HasValue, s => s.Price >= input.PriceStart.Value)
.WhereIf(input.PriceEnd.HasValue, s => s.Price <= input.PriceEnd.Value)
//銷售價區(qū)間查詢
.WhereIf(input.SalePriceStart.HasValue, s => s.SalePrice >= input.SalePriceStart.Value)
.WhereIf(input.SalePriceEnd.HasValue, s => s.SalePrice <= input.SalePriceEnd.Value)
//特價區(qū)間查詢
.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
//最低折扣區(qū)間查詢
.WhereIf(input.LowestDiscountStart.HasValue, s => s.LowestDiscount >= input.LowestDiscountStart.Value)
.WhereIf(input.LowestDiscountEnd.HasValue, s => s.LowestDiscount <= input.LowestDiscountEnd.Value)
//創(chuàng)建日期區(qū)間查詢
.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)
{
//按創(chuàng)建時間倒序排序
return base.ApplySorting(query, input).OrderByDescending(s => s.CreationTime);//時間降序
}
雖然我們一般在界面上不會放置所有的條件,但是高級查詢模塊倒是可以把分頁條件DTO里面的條件全部擺上去的强胰。
高級查詢模塊的條件如下所示舱沧。
我們高級查詢里面的條件還是以GetAll里面的對象分頁查詢Dto里面的屬性,我們需要根據(jù)這些條件進行構(gòu)建哪廓,也需要以這些屬性的類型進行一個控件的選擇狗唉。
因此我們需要一個屬性的名稱說明,以及在高級查詢模塊的列表界面中對顯示那些字段進行控制涡真,如下代碼所示分俯。
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> 的處理肾筐,我們把分頁對象的查詢屬性和類型賦值給了高級查詢模塊,讓它根據(jù)類型來創(chuàng)建不同的輸入顯示缸剪,如常規(guī)的字符串吗铐、數(shù)值區(qū)段、日期區(qū)段杏节,下拉列表等等唬渗。
對于下拉列表,我們需要綁定它的數(shù)據(jù)源奋渔,如下代碼所示镊逝。
dlg.AddColumnListItem("ProductType", await DictItemUtil.GetDictListItemByDictType("產(chǎn)品類型"));//字典列表
dlg.AddColumnListItem("Status", await DictItemUtil.GetDictListItemByDictType("產(chǎn)品狀態(tài)"));//字典列表
而對于一些常規(guī)的固定列表,也可以以類似的方式加入下拉列表
//固定轉(zhuǎn)義的列表
var specialList = new List<CListItem>() { new CListItem("特價", "True"), new CListItem("一般", "False") };
dlg.AddColumnListItem("IsUseSpecial", specialList);
或者
dlg.AddColumnListItem("Sex", "男,女");//固定列表
因此整個調(diào)用高級查詢模塊的代碼如下所示
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 下拉列表數(shù)據(jù)
dlg.AddColumnListItem("ProductType", await DictItemUtil.GetDictListItemByDictType("產(chǎn)品類型"));//字典列表
dlg.AddColumnListItem("Status", await DictItemUtil.GetDictListItemByDictType("產(chǎn)品狀態(tài)"));//字典列表
//固定轉(zhuǎn)義的列表
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"));//動態(tài)列表
#endregion
dlg.ConditionChanged += new FrmAdvanceSearch.ConditionChangedEventHandler(dlg_ConditionChanged);
}
dlg.ShowDialog();
}
在處理獲取數(shù)據(jù)GetData函數(shù)的時候嫉鲸,我們需要根據(jù)高級查詢進行一定的切換撑蒜,以便顯示正確的過濾條件,如下代碼所示是獲取數(shù)據(jù)的處理玄渗。
/// <summary>
/// 獲取數(shù)據(jù)
/// </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
{
//構(gòu)建分頁的條件和查詢條件
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(),
};
//日期和數(shù)值范圍定義
//創(chuàng)建時間座菠,需在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對象浴滴,就可以構(gòu)建出我們需要的分頁查詢條件,傳遞給Web API端獲取對應(yīng)條件的數(shù)據(jù)了岁钓。
pagerDto = new ProductPagedDto(this.winGridViewPager1.PagerInfo);
pagerDto = dlg.GetPagedResult(pagerDto);
而高級查詢模塊升略,所需要處理的邏輯就是需要根據(jù)不同的屬性類型,賦值常規(guī)的屬性值或者區(qū)段屬性值甜紫,從而構(gòu)建出分頁對應(yīng)的屬性條件即可降宅。
如果是區(qū)段(包括日期或者數(shù)值)的,我們分頁查詢條件里面囚霸,會有一個ABCStart,ABCEnd的對象屬性腰根,依照這個規(guī)則,獲取到對應(yīng)的用戶輸入拓型,采用反射方式賦值DTO對象即可额嘿。