天天看點

ABP開發架構前後端開發系列---(6)ABP基礎接口處理和省份城市行政區管理子產品的開發

 ​

最近沒有更新ABP架構的相關文章,一直在研究和封裝相關的接口,總算告一段落,開始繼續整理下開發心得。上次我在随筆《​​ABP開發架構前後端開發系列---(5)Web API調用類在Winform項目中的使用​​》中介紹了字典子產品的管理,以及實作了正常的擷取所有記錄,擷取條件查詢記錄,建立、更新、删除這些接口。本篇繼續深入介紹ABP架構在實際項目中使用的情況,本篇随筆整理對ABP基礎接口,以及展示完成的省份城市行政區管理子產品的内容。

1、ABP正常處理接口

根據ABP架構預設提供的一些接口,我們可以在服務端封裝好相關的Web API接口(由于動态API的便利,其實是完成ApplicationService層即可),前面介紹了擷取條件查詢記錄,建立、更新、删除這些接口的實作和處理,以及可以擴充自己的自定義業務接口,如下是字典子產品的接口關系。

ABP開發架構前後端開發系列---(6)ABP基礎接口處理和省份城市行政區管理子產品的開發

字典管理界面,列出字典類型,并對字典類型下的字典資料進行分頁展示,分頁展示利用分頁控件展示。

ABP開發架構前後端開發系列---(6)ABP基礎接口處理和省份城市行政區管理子產品的開發

新增或者編輯窗體界面如下

ABP開發架構前後端開發系列---(6)ABP基礎接口處理和省份城市行政區管理子產品的開發

或者是批量的字典資料錄入

ABP開發架構前後端開發系列---(6)ABP基礎接口處理和省份城市行政區管理子產品的開發

這個精确或者模糊查詢,則是在應用服務層裡面定義規則的,在應用服務層接口類裡面,重寫CreateFilteredQuery可以設定GetAll的查詢規則,重寫ApplySorting則可以指定清單的排序順序。

ABP開發架構前後端開發系列---(6)ABP基礎接口處理和省份城市行政區管理子產品的開發

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檔案裡面,友善管理,如下所示。

ABP開發架構前後端開發系列---(6)ABP基礎接口處理和省份城市行政區管理子產品的開發

上面是字典子產品的一些基礎介紹,實際上我們開發業務子產品的時候,錄入資料的時候,還需要一個判斷的步驟,如不允許名稱重複的情況。在建立新的記錄和更新已有記錄都需要進行必要的判斷,保證資料的有效性和不重複性。

如對于省份管理界面來說,我們不能運作重複錄入省份名稱,那麼就需要在錄入資料或者更新資料的時候,進行必要的存在性判斷。

ABP開發架構前後端開發系列---(6)ABP基礎接口處理和省份城市行政區管理子產品的開發

那麼上面的處理是如何實作的呢。

主要的界面實作代碼如下所示。

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 我們在分頁條件裡面增加一個固定的屬性即可。

ABP開發架構前後端開發系列---(6)ABP基礎接口處理和省份城市行政區管理子產品的開發

以上的分頁資訊,包含了實體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);
        }