实现 定义按任意字段关键字查询过滤器(IKeywordOrientedFilter)接口,查询实体列表Dto若实现该接口,将筛选指定的目标字段(TargetFields)包含指定的关键字(Keyword)的实体。
1 2 3 4 5 6 7 public interface IKeywordOrientedFilter { public string Keyword { get; set; } public string TargetFields { get; set; } }
创建应用过滤条件方法:ApplySearchFiltered,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected virtual IQueryable<TEntity> ApplySearchFiltered(IQueryable<TEntity> query, TGetListInput input) { if (input is IKeywordOrientedFilter) { var filteredInput = input as IKeywordOrientedFilter; if (filteredInput != null) { var targetFields = new string[] { "Name", "Title" }; if (!string.IsNullOrEmpty(filteredInput.TargetFields)) { targetFields = filteredInput.TargetFields.Split(','); } return query.WhereIf(!filteredInput.Keyword.IsNullOrWhiteSpace(), FilterByKeywordDynamic<TEntity>(filteredInput.Keyword, targetFields)); } } return query; }
请注意,可应用过滤的条件为:
input需实现IKeywordOrientedFilter接口,且Keyword不为空;
若filteredInput.TargetFields为空,则默认使用Name和Title字段进行筛选。
对于每一个TargetField,需要在实体中找到对应字段(属性)。若找到,则为此实体字段创建条件筛选的表达式,然后将这些表达式通过Or连接起来,最终返回一个包含多段关键字筛选的Lambda表达式。
创建FilterByKeywordDynamic方法,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 private Expression<Func<TEntity, bool>> FilterByKeywordDynamic<T>(string keyword, params string[] sortColumns) { var parameter = Expression.Parameter(typeof(T), "p"); var propertys = sortColumns.Select(sortColumn => typeof(T).GetProperty(sortColumn)); var method = typeof(string) .GetMethods() .FirstOrDefault(x => x.Name == "Contains"); var keyConstantExpression = Expression.Constant(keyword, typeof(string)); Expression originalExpression = null; foreach (var property in propertys) { if (property != null) { var propertyAccess = Expression.MakeMemberAccess(parameter, property); var expression = Expression.Call(propertyAccess, method, keyConstantExpression); if (originalExpression == null) { originalExpression = expression; } else { originalExpression = Expression.Or(originalExpression, expression); } } } var result = originalExpression != null ? Expression.Lambda<Func<TEntity, bool>>(originalExpression, parameter) : p => true; return result; }
创建默认的应用过滤规则DefaultConvention,将之前的按组织架构查询和按关键字查询的代码提取到DefaultConvention方法中,此类可派生,使用virtual关键字以便在子类中重写,代码如下:
1 2 3 4 5 6 protected virtual async Task<IQueryable<TEntity>> DefaultConvention(TGetListInput input, IQueryable<TEntity> query) { query = ApplySearchFiltered(query, input); query = ApplyUserOrientedFiltered(query, input); return query; }
在CreateBriefFilteredQueryAsync和CreateFilteredQueryAsync方法中调用DefaultConvention方法,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 protected virtual async Task<IQueryable<TEntity>> CreateBriefFilteredQueryAsync(TGetListBriefInput input) { var query = await ReadOnlyRepository.GetQueryableAsync(); query = await DefaultConvention(input, query); return query; } protected override async Task<IQueryable<TEntity>> CreateFilteredQueryAsync(TGetListInput input) { var query = await ReadOnlyRepository.GetQueryableAsync(); query = await DefaultConvention(input, query); return query; }
应用 无需在应用层中更改代码,
在GetAllAlarmInput中实现IKeywordOrientedFilter接口,代码如下:
1 2 3 4 5 6 7 8 9 public class GetAllAlarmInput : PagedAndSortedResultRequestDto, IKeywordOrientedFilter { //keyword public string Keyword { get; set; } public string TargetFields { get; set; } ... }
测试 在告警管理页面建立一些告警
在筛选中输入关键字“3”,点击查询
可以看到将筛选出标题包含关键字“3”的告警
查询的报文Payload如下图: