ABP開發框架前後端開發系列---(6)ABP基礎介面處理和省份城市行政區管理模組的開發
最近沒有更新ABP框架的相關文章,一直在研究和封裝相關的介面,總算告一段落,開始繼續整理下開發心得。上次我在隨筆《ABP開發框架前後端開發系列---(5)Web API呼叫類在Winform專案中的使用》中介紹了字典模組的管理,以及實現了常規的獲取所有記錄,獲取條件查詢記錄,建立、更新、刪除這些介面。本篇繼續深入介紹ABP框架在實際專案中使用的情況,本篇隨筆整理對ABP基礎介面,以及展示完成的省份城市行政區管理模組的內容。
1、ABP常規處理介面
根據ABP框架預設提供的一些介面,我們可以在服務端封裝好相關的Web API介面(由於動態API的便利,其實是完成ApplicationService層即可),前面介紹了獲取條件查詢記錄,建立、更新、刪除這些介面的實現和處理,以及可以擴充套件自己的自定義業務介面,如下是字典模組的介面關係。
字典管理介面,列出字典型別,並對字典型別下的字典資料進行分頁展示,分頁展示利用分頁控制元件展示。
新增或者編輯窗體介面如下
或者是批量的字典資料錄入
這個精確或者模糊查詢,則是在應用服務層裡面定義規則的,在應用服務層介面類裡面,重寫CreateFilteredQuery可以設定GetAll的查詢規則,重寫ApplySorting則可以指定列表的排序順序。
2、ABP常規查詢介面的細化
在前面介紹了的內容彙總,基本上實現了常規資料的分頁查詢,我們可以看到,對於字典資料來說,分頁查詢條件是在DictDataPagedDto裡面定義,這個是我們定義的分頁條件,如下程式碼所示。
/// <summary> /// 用於根據條件分頁查詢 /// </summary> public class DictDataPagedDto : PagedResultRequestDto { /// <summary> /// 字典型別ID /// </summary> public virtual string DictType_ID { get; set; } /// <summary> /// 型別名稱 /// </summary> public virtual string Name { get; set; } /// <summary> /// 指定值 /// </summary> public virtual string Value { get; set; } /// <summary> /// 備註 /// </summary> public virtual string Remark { get; set; } }
這個類檔案,我們一般把這個業務模組相關的統一放在一個檔案中,例如字典資料相關的DTO放在一個DictDataDto檔案裡面,方便管理,如下所示。
上面是字典模組的一些基礎介紹,實際上我們開發業務模組的時候,錄入資料的時候,還需要一個判斷的步驟,如不允許名稱重複的情況。在建立新的記錄和更新已有記錄都需要進行必要的判斷,保證資料的有效性和不重複性。
如對於省份管理介面來說,我們不能執行重複錄入省份名稱,那麼就需要在錄入資料或者更新資料的時候,進行必要的存在性判斷。
那麼上面的處理是如何實現的呢。
主要的介面實現程式碼如下所示。
if (string.IsNullOrEmpty(ID)) { //判斷存在條件 var countDto = new ProvincePagedDto() { ProvinceName = this.txtProvince.Text }; bool isExist = await ProvinceApiCaller.Instance.Count(countDto) > 0; if (isExist) { MessageDxUtil.ShowTips("省份名稱已存在,請選擇其他名稱"); this.txtProvince.Focus(); return; } else { //建立新記錄 tempInfo = await ProvinceApiCaller.Instance.Create(tempInfo); } } else { //判斷存在條件,排除本記錄同名情況 var countDto = new ProvincePagedDto() { ProvinceName = this.txtProvince.Text, ExcludeId = ID.ToInt64() }; bool isExist = await ProvinceApiCaller.Instance.Count(countDto) > 0; if (isExist) { MessageDxUtil.ShowTips("省份名稱已存在,請選擇其他名稱"); this.txtProvince.Focus(); return; } else { //更新記錄 tempInfo = await ProvinceApiCaller.Instance.Update(tempInfo); } } ProcessDataSaved(this.btnOK, new EventArgs()); this.DialogResult = System.Windows.Forms.DialogResult.OK;
我們發現,這裡增加了一個Count的函式用來判斷,傳入的條件就是前面的分頁請求條件。
bool isExist = await ProvinceApiCaller.Instance.Count(countDto) > 0;
我們看看我們的應用服務層的介面實現如下所示。
/// <summary> /// 獲取指定條件的數量 /// </summary> /// <param name="input">查詢條件</param> /// <returns></returns> public async virtual Task<int> Count(TGetAllInput input) { var query = CreateFilteredQuery(input); return await Task.FromResult(query.Count()); }
這裡最終還是跳轉到 CreateFilteredQuery 函式裡面實現判斷邏輯了。
/// <summary> /// 自定義條件處理 /// </summary> /// <param name="input">查詢條件Dto</param> /// <returns></returns> protected override IQueryable<Province> CreateFilteredQuery(ProvincePagedDto input) { return base.CreateFilteredQuery(input) .WhereIf(input.ExcludeId.HasValue, t=>t.Id != input.ExcludeId) //不包含排除ID .WhereIf(!input.ProvinceName.IsNullOrWhiteSpace(), t => t.ProvinceName.Contains(input.ProvinceName)); }
這裡麵包含了兩個判斷條件,一個是排除指定的ID記錄,一個是匹配省份名稱。
因為我們在更新記錄的時候,需要判斷非本記錄是否有重複的名稱。
//判斷存在條件,排除本記錄同名情況 var countDto = new ProvincePagedDto() { ProvinceName = this.txtProvince.Text, ExcludeId = ID.ToInt64() }; bool isExist = await ProvinceApiCaller.Instance.Count(countDto) > 0;
這個ExcludeId 我們在分頁條件裡面增加一個固定的屬性即可。
以上的分頁資訊,包含了實體DTO物件的一些屬性,我們可以根據需要增加或者減少一部分屬性。
另外我們定義的建立省份Dto物件和獲取到單個實體的DTO物件,他們的定義和關係如下所示,方便我們在介面上進行操作。
/// <summary> /// 建立全國省份表,DTO物件 /// </summary> public class CreateProvinceDto : EntityDto<long> { /// <summary> /// 預設建構函式(需要初始化屬性的在此處理) /// </summary> public CreateProvinceDto() { } #region Property Members /// <summary> /// 省份名稱 /// </summary> [Required] public virtual string ProvinceName { get; set; } #endregion } /// <summary> /// 全國省份表,DTO物件 /// </summary> public class ProvinceDto : CreateProvinceDto { }
固定這些規則後,我們也可以用程式碼生成工具快速生成對應的DTO檔案了。
有了這些分頁屬性後,我們就可以在應用服務層裡面定義自己的過濾規則了,如對於字典型別的應用服務層的篩選條件函式,如下所示。
/// <summary> /// 自定義條件處理 /// </summary> /// <param name="input"></param> /// <returns></returns> protected override IQueryable<DictType> CreateFilteredQuery(DictTypePagedDto input) { return base.CreateFilteredQuery(input) .WhereIf(!string.IsNullOrEmpty(input.ExcludeId), t => t.Id != input.ExcludeId) //不包含排除ID .WhereIf(!string.IsNullOrEmpty(input.Name), t => t.Name.Contains(input.Name)) .WhereIf(!string.IsNullOrEmpty(input.Remark), t => t.Remark.Contains(input.Remark)) .WhereIf(!string.IsNullOrEmpty(input.Code), t => t.Code == input.Code) .WhereIf(!string.IsNullOrEmpty(input.PID), t => t.PID == input.PID); }
上面是對於包含、相等或者不等於的三種情況的條件判斷,如果我們還需要一個時間區間範圍或者數值範圍的判斷,那麼同樣可以在這裡進行管理規則,如下是針對產品應用服務層的過濾規則,如下程式碼所示。
/// <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); }
以上就是我們深入對分頁查詢和判斷是否存在介面的細節處理,可以包含很多自定義的條件,如等於或不等於、包含或者不包含,區間查詢(大於或者小於等)條件的處理。對於省份城市行政區管理模組的重複性判斷,我們通過Count函式來判斷,同時在後臺應用服務層對這些引數進行規則過濾即可。
&n