之前我們實(shí)現(xiàn)了Employee,Alarm管理模塊以及通用查詢應(yīng)用層。
Employee的集合查詢業(yè)務(wù),是通過重寫CreateFilteredQueryAsync方法,來實(shí)現(xiàn)按組織架構(gòu)查詢的過濾條件。
我們將這段邏輯代碼提取到通用查詢應(yīng)用層中,便可實(shí)現(xiàn)在任何業(yè)務(wù)的按組織架構(gòu)查詢。
原理
查詢依據(jù)
在Abp中,組織架構(gòu)和用戶是通過中間表AbpUserOrganizationUnits實(shí)現(xiàn)多對(duì)多的關(guān)系。模型如下圖所示:
查詢目標(biāo)業(yè)務(wù)對(duì)象HealthAlarm關(guān)聯(lián)了業(yè)務(wù)用戶HealthClient,因業(yè)務(wù)用戶與鑒權(quán)用戶IdentityUser共享同一個(gè)Id,因此可以通過查詢組織架構(gòu)關(guān)聯(lián)的User,查詢到業(yè)務(wù)對(duì)象。
通過LINQ查詢
EmployeeAppService中,CreateFilteredQueryAsync方法組織架構(gòu)的過濾條件代碼如下:
var organizationUnitUsers = await organizationUnitAppService.GetOrganizationUnitUsersAsync(new GetOrganizationUnitUsersInput()
{
Id = input.OrganizationUnitId.Value
});
if (organizationUnitUsers.Count() > 0)
{
var ids = organizationUnitUsers.Select(c => c.Id);
query = query.Where(t => ids.Contains(t.Id));
}
else
{
query = query.Where(c => false);
}
通過反射和動(dòng)態(tài)Lambda表達(dá)式查詢
CreateFilteredQueryAsync是通過業(yè)務(wù)用戶的IRepository獲取實(shí)體的IQueryable 然后通過query.Where()實(shí)現(xiàn)了按組織架構(gòu)的過濾條件。
IQueryable是一泛型類接口,泛型參數(shù)是實(shí)體類。要想在任意實(shí)體實(shí)現(xiàn)Where的過濾條件,我們使用動(dòng)態(tài)拼接語言集成查詢 (LINQ) 的方式實(shí)現(xiàn)通用查詢接口,有關(guān)LINQ表達(dá)式,請(qǐng)閱讀 LINQ 教程和有關(guān) Lambda 表達(dá)式的文章。
實(shí)現(xiàn)
定義按組織架構(gòu)查詢過濾器(IOrganizationOrientedFilter)接口,查詢實(shí)體列表Dto若實(shí)現(xiàn)該接口,將篩選指定 OrganizationUnitId 下的用戶關(guān)聯(lián)的實(shí)體。
public interface IOrganizationOrientedFilter
{
Guid? OrganizationUnitId { get; set; }
}
重寫CreateFilteredQueryAsync方法,代碼如下
protected override async Task<IQueryable<TEntity>> CreateFilteredQueryAsync(TGetListInput input)
{
var query = await ReadOnlyRepository.GetQueryableAsync();
query = await ApplyOrganizationOrientedFiltered(query,input);
return query;
}
對(duì)于OrganizationUnit服務(wù),其依賴關(guān)系在應(yīng)用層,查找指定組織架構(gòu)的用戶將在CurdAppServiceBase的子類實(shí)現(xiàn)。創(chuàng)建一個(gè)抽象方法GetUserIdsByOrganizationAsync
protected abstract Task<IEnumerable<Guid>> GetUserIdsByOrganizationAsync(Guid organizationUnitId)
創(chuàng)建應(yīng)用過濾條件方法:ApplyOrganizationOrientedFiltered,在此實(shí)現(xiàn)拼接LINQ表達(dá)式,代碼如下:
protected virtual async Task<IQueryable<TEntity>> ApplyOrganizationOrientedFiltered(IQueryable<TEntity> query, TGetListInput input)
{
if (input is IOrganizationOrientedFilter && HasProperty<TEntity>("UserId"))
{
var property = typeof(TEntity).GetProperty("UserId");
var filteredInput = input as IOrganizationOrientedFilter;
if (filteredInput != null && filteredInput.OrganizationUnitId.HasValue)
{
var ids = await GetUserIdsByOrganizationAsync(filteredInput.OrganizationUnitId.Value);
Expression originalExpression = null;
var parameter = Expression.Parameter(typeof(TEntity), "p");
foreach (var id in ids)
{
var keyConstantExpression = Expression.Constant(id, typeof(Guid));
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var expressionSegment = Expression.Equal(propertyAccess, keyConstantExpression);
if (originalExpression == null)
{
originalExpression = expressionSegment;
}
else
{
originalExpression = Expression.Or(originalExpression, expressionSegment);
}
}
var equalExpression = originalExpression != null ?
Expression.Lambda<Func<TEntity, bool>>(originalExpression, parameter)
: p => false;
query = query.Where(equalExpression);
}
}
return query;
}
請(qǐng)注意,可應(yīng)用過濾的條件為:
- input需實(shí)現(xiàn)IOrganizationOrientedFilter接口
- 實(shí)體必須包含UserId字段
否則將原封不動(dòng)返回IQueryable對(duì)象。
應(yīng)用
在上一章Alarm管理模塊中,我們已經(jīng)寫好了AlarmAppService,我們需要為其實(shí)現(xiàn)GetUserIdsByOrganizationAsync方法。改造AlarmAppService代碼如下:
public class AlarmAppService : ExtendedCurdAppServiceBase<Matoapp.Health.Alarm.Alarm, AlarmDto, AlarmDto, AlarmBriefDto, long, GetAllAlarmInput, GetAllAlarmInput, CreateAlarmInput, UpdateAlarmInput>, IAlarmAppService
{
private readonly IOrganizationUnitAppService organizationUnitAppService;
public AlarmAppService(
IOrganizationUnitAppService organizationUnitAppService,
IRepository<Matoapp.Health.Alarm.Alarm, long> basicInventoryRepository) : base(basicInventoryRepository)
{
this.organizationUnitAppService = organizationUnitAppService;
}
protected override async Task<IEnumerable<Guid>> GetUserIdsByOrganizationAsync(Guid organizationUnitId)
{
var organizationUnitUsers = await organizationUnitAppService.GetOrganizationUnitUsersAsync(new GetOrganizationUnitUsersInput()
{
Id = organizationUnitId
});
var ids = organizationUnitUsers.Select(c => c.Id);
return ids;
}
}
在GetAllAlarmInput中實(shí)現(xiàn)IOrganizationOrientedFilter接口,代碼如下:
public class GetAllAlarmInput : PagedAndSortedResultRequestDto, IOrganizationOrientedFilter
{
public Guid? OrganizationUnitId { get; set; }
...
}
測(cè)試
創(chuàng)建一些組織架構(gòu),命名“群組”
在不同“群組”下創(chuàng)建一些客戶(Client)
在告警管理頁面中,創(chuàng)建一些告警,并將這些告警分配給不同的客戶
在客戶管理中,通過選擇不同的組織架構(gòu),查詢當(dāng)前“群組”下的客戶告警文章來源:http://www.zghlxwxcb.cn/news/detail-558836.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-558836.html
到了這里,關(guān)于怎樣優(yōu)雅地增刪查改(五):按組織架構(gòu)查詢的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!