最近沒(méi)有更新ABP框架的相關(guān)文章宜咒,一直在研究和封裝相關(guān)的接口无虚,總算告一段落踢俄,開(kāi)始繼續(xù)整理下開(kāi)發(fā)心得咪橙。上次我在隨筆《ABP開(kāi)發(fā)框架前后端開(kāi)發(fā)系列---(5)Web API調(diào)用類(lèi)在Winform項(xiàng)目中的使用》中介紹了字典模塊的管理,以及實(shí)現(xiàn)了常規(guī)的獲取所有記錄愁拭,獲取條件查詢記錄讲逛,創(chuàng)建、更新岭埠、刪除這些接口盏混。本篇繼續(xù)深入介紹ABP框架在實(shí)際項(xiàng)目中使用的情況,本篇隨筆整理對(duì)ABP基礎(chǔ)接口惜论,以及展示完成的省份城市行政區(qū)管理模塊的內(nèi)容许赃。
1、ABP常規(guī)處理接口
根據(jù)ABP框架默認(rèn)提供的一些接口馆类,我們可以在服務(wù)端封裝好相關(guān)的Web API接口(由于動(dòng)態(tài)API的便利混聊,其實(shí)是完成ApplicationService層即可),前面介紹了獲取條件查詢記錄乾巧,創(chuàng)建句喜、更新预愤、刪除這些接口的實(shí)現(xiàn)和處理,以及可以擴(kuò)展自己的自定義業(yè)務(wù)接口咳胃,如下是字典模塊的接口關(guān)系植康。
字典管理界面,列出字典類(lèi)型展懈,并對(duì)字典類(lèi)型下的字典數(shù)據(jù)進(jìn)行分頁(yè)展示销睁,分頁(yè)展示利用分頁(yè)控件展示。
新增或者編輯窗體界面如下
或者是批量的字典數(shù)據(jù)錄入
這個(gè)精確或者模糊查詢存崖,則是在應(yīng)用服務(wù)層里面定義規(guī)則的冻记,在應(yīng)用服務(wù)層接口類(lèi)里面,重寫(xiě)CreateFilteredQuery可以設(shè)置GetAll的查詢規(guī)則来惧,重寫(xiě)ApplySorting則可以指定列表的排序順序盒揉。
2厅缺、ABP常規(guī)查詢接口的細(xì)化
在前面介紹了的內(nèi)容匯總孤荣,基本上實(shí)現(xiàn)了常規(guī)數(shù)據(jù)的分頁(yè)查詢契邀,我們可以看到,對(duì)于字典數(shù)據(jù)來(lái)說(shuō)趁曼,分頁(yè)查詢條件是在DictDataPagedDto里面定義,這個(gè)是我們定義的分頁(yè)條件棕洋,如下代碼所示挡闰。
/// <summary>
/// 用于根據(jù)條件分頁(yè)查詢
/// </summary>
public class DictDataPagedDto : PagedResultRequestDto
{
/// <summary>
/// 字典類(lèi)型ID
/// </summary>
public virtual string DictType_ID { get; set; }
/// <summary>
/// 類(lèi)型名稱(chēng)
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 指定值
/// </summary>
public virtual string Value { get; set; }
/// <summary>
/// 備注
/// </summary>
public virtual string Remark { get; set; }
}
這個(gè)類(lèi)文件,我們一般把這個(gè)業(yè)務(wù)模塊相關(guān)的統(tǒng)一放在一個(gè)文件中掰盘,例如字典數(shù)據(jù)相關(guān)的DTO放在一個(gè)DictDataDto文件里面摄悯,方便管理,如下所示愧捕。
上面是字典模塊的一些基礎(chǔ)介紹奢驯,實(shí)際上我們開(kāi)發(fā)業(yè)務(wù)模塊的時(shí)候,錄入數(shù)據(jù)的時(shí)候次绘,還需要一個(gè)判斷的步驟瘪阁,如不允許名稱(chēng)重復(fù)的情況。在創(chuàng)建新的記錄和更新已有記錄都需要進(jìn)行必要的判斷邮偎,保證數(shù)據(jù)的有效性和不重復(fù)性管跺。
如對(duì)于省份管理界面來(lái)說(shuō),我們不能運(yùn)行重復(fù)錄入省份名稱(chēng)禾进,那么就需要在錄入數(shù)據(jù)或者更新數(shù)據(jù)的時(shí)候豁跑,進(jìn)行必要的存在性判斷。
那么上面的處理是如何實(shí)現(xiàn)的呢泻云。
主要的界面實(shí)現(xiàn)代碼如下所示艇拍。
if (string.IsNullOrEmpty(ID))
{
//判斷存在條件
var countDto = new ProvincePagedDto() { ProvinceName = this.txtProvince.Text };
bool isExist = await ProvinceApiCaller.Instance.Count(countDto) > 0;
if (isExist)
{
MessageDxUtil.ShowTips("省份名稱(chēng)已存在狐蜕,請(qǐng)選擇其他名稱(chēng)");
this.txtProvince.Focus();
return;
}
else
{
//創(chuàng)建新記錄
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("省份名稱(chēng)已存在,請(qǐng)選擇其他名稱(chēng)");
this.txtProvince.Focus();
return;
}
else
{
//更新記錄
tempInfo = await ProvinceApiCaller.Instance.Update(tempInfo);
}
}
ProcessDataSaved(this.btnOK, new EventArgs());
this.DialogResult = System.Windows.Forms.DialogResult.OK;
我們發(fā)現(xiàn)卸夕,這里增加了一個(gè)Count的函數(shù)用來(lái)判斷层释,傳入的條件就是前面的分頁(yè)請(qǐng)求條件。
bool isExist = await ProvinceApiCaller.Instance.Count(countDto) > 0;
我們看看我們的應(yīng)用服務(wù)層的接口實(shí)現(xiàn)如下所示娇哆。
/// <summary>
/// 獲取指定條件的數(shù)量
/// </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());
}
這里最終還是跳轉(zhuǎn)到 CreateFilteredQuery 函數(shù)里面實(shí)現(xiàn)判斷邏輯了湃累。
/// <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));
}
這里面包含了兩個(gè)判斷條件,一個(gè)是排除指定的ID記錄碍讨,一個(gè)是匹配省份名稱(chēng)治力。
因?yàn)槲覀冊(cè)诟掠涗浀臅r(shí)候,需要判斷非本記錄是否有重復(fù)的名稱(chēng)勃黍。
//判斷存在條件,排除本記錄同名情況
var countDto = new ProvincePagedDto() { ProvinceName = this.txtProvince.Text, ExcludeId = ID.ToInt64() };
bool isExist = await ProvinceApiCaller.Instance.Count(countDto) > 0;
這個(gè)ExcludeId 我們?cè)诜猪?yè)條件里面增加一個(gè)固定的屬性即可宵统。
以上的分頁(yè)信息,包含了實(shí)體DTO對(duì)象的一些屬性覆获,我們可以根據(jù)需要增加或者減少一部分屬性马澈。
另外我們定義的創(chuàng)建省份Dto對(duì)象和獲取到單個(gè)實(shí)體的DTO對(duì)象,他們的定義和關(guān)系如下所示弄息,方便我們?cè)诮缑嫔线M(jìn)行操作痊班。
/// <summary>
/// 創(chuàng)建全國(guó)省份表,DTO對(duì)象
/// </summary>
public class CreateProvinceDto : EntityDto<long>
{
/// <summary>
/// 默認(rèn)構(gòu)造函數(shù)(需要初始化屬性的在此處理)
/// </summary>
public CreateProvinceDto()
{
}
#region Property Members
/// <summary>
/// 省份名稱(chēng)
/// </summary>
[Required]
public virtual string ProvinceName { get; set; }
#endregion
}
/// <summary>
/// 全國(guó)省份表摹量,DTO對(duì)象
/// </summary>
public class ProvinceDto : CreateProvinceDto
{
}
固定這些規(guī)則后涤伐,我們也可以用代碼生成工具快速生成對(duì)應(yīng)的DTO文件了。
有了這些分頁(yè)屬性后缨称,我們就可以在應(yīng)用服務(wù)層里面定義自己的過(guò)濾規(guī)則了凝果,如對(duì)于字典類(lèi)型的應(yīng)用服務(wù)層的篩選條件函數(shù),如下所示睦尽。
/// <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);
}
上面是對(duì)于包含器净、相等或者不等于的三種情況的條件判斷,如果我們還需要一個(gè)時(shí)間區(qū)間范圍或者數(shù)值范圍的判斷当凡,那么同樣可以在這里進(jìn)行管理規(guī)則山害,如下是針對(duì)產(chǎn)品應(yīng)用服務(wù)層的過(guò)濾規(guī)則,如下代碼所示沿量。
/// <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)
//成本價(jià)區(qū)間查詢
.WhereIf(input.PriceStart.HasValue, s => s.Price >= input.PriceStart.Value)
.WhereIf(input.PriceEnd.HasValue, s => s.Price <= input.PriceEnd.Value)
//銷(xiāo)售價(jià)區(qū)間查詢
.WhereIf(input.SalePriceStart.HasValue, s => s.SalePrice >= input.SalePriceStart.Value)
.WhereIf(input.SalePriceEnd.HasValue, s => s.SalePrice <= input.SalePriceEnd.Value)
//特價(jià)區(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);
}
以上就是我們深入對(duì)分頁(yè)查詢和判斷是否存在接口的細(xì)節(jié)處理粗恢,可以包含很多自定義的條件,如等于或不等于欧瘪、包含或者不包含眷射,區(qū)間查詢(大于或者小于等)條件的處理。對(duì)于省份城市行政區(qū)管理模塊的重復(fù)性判斷,我們通過(guò)Count函數(shù)來(lái)判斷妖碉,同時(shí)在后臺(tái)應(yīng)用服務(wù)層對(duì)這些參數(shù)進(jìn)行規(guī)則過(guò)濾即可涌庭。