【发布时间】:2021-04-23 08:52:56
【问题描述】:
我有一个自定义过滤器表达式,用户可以将字典发送到我的 api,我将创建一个自定义 where 子句。我不是编写自定义 LINQ 的专家,所以如果有更好的方法,那就太好了。
所有这些都有效(没有错误),但它没有应用我的过滤,因此返回它可以找到的所有内容)
我在其中添加自定义过滤器的存储库调用(查看“FilterByString”区域) . _entities 是一个 DbSet
// This is in my contructor
private readonly DbSet<T2> _entities;
_entities = _context.Set<T2>();
public async Task<BasePagedResponse<T1>> PagedList(Guid companyId, int pageNumber, int pageSize, Dictionary<string, string> filterParameters, Expression<Func<T2, bool>> predicate, Func<IQueryable<T2>, IIncludableQueryable<T2, object>> including = null)
{
try
{
var modelList = await _entities
.AsQueryable()
.Where(predicate)
.CustomInclude(including)
.FilterByString(filterParameters)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize).ToListAsync();
var mappedList = _mapper.Map<List<T1>>(modelList);
var total = await GetTotalRecords(companyId);
var pagedResult = new PagedResult<T1>(mappedList, total, pageNumber, pageSize);
return new BasePagedResponse<T1>(pagedResult, true, null);
}
catch (SqlException ex)
{
return new BasePagedResponse<T1>(null, false, new[] { new Error(GlobalVariables.error_list, $"Error listing models-({typeof(T1).Name}). {ex.Message}") });
}
}
我的静态 SQL 助手,它接受源查询并附加我的自定义 Where 子句
public static IQueryable<T> FilterByString<T>(this IQueryable<T> source, Dictionary<string, string> filterParameters = null)
{
if (filterParameters != null)
{
foreach (var keyValuePair in filterParameters)
{
source.Where(Filter<T>(keyValuePair.Key, keyValuePair.Value));
}
}
return source;
}
我的自定义“过滤器”(看起来很多,但它只是查找要过滤的字符串、bool 或 int 类型)
private static Expression<Func<T, bool>> Filter<T>(string propertyName, string queryText)
{
var parameter = Expression.Parameter(typeof(T), "entity");
var getter = Expression.Property(parameter, propertyName);
if (getter.Type == typeof(string))
{
var stringContainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsCall = Expression.Call(getter, stringContainsMethod,
Expression.Constant(queryText, typeof(string)));
return Expression.Lambda<Func<T, bool>>(containsCall, parameter);
}
if (getter.Type == typeof(int))
{
var stringEqualsMethod = typeof(int).GetMethod("Equals", new[] { typeof(int) });
var equalsCall = Expression.Call(getter, stringEqualsMethod,
Expression.Constant(value: Int32.Parse(queryText), typeof(Int32)));
return Expression.Lambda<Func<T, bool>>(equalsCall, parameter);
}
if (getter.Type == typeof(bool))
{
var stringEqualsMethod = typeof(bool).GetMethod("Equals", new[] { typeof(bool) });
var equalsCall = Expression.Call(getter, stringEqualsMethod,
Expression.Constant(value: bool.Parse(queryText), typeof(bool)));
return Expression.Lambda<Func<T, bool>>(equalsCall, parameter);
}
throw new Exception("No proper type defined for Filter Parameter. Supports only String, Int and Boolean");
}
【问题讨论】:
-
附带说明:构建处理所有过滤器的一个谓词(通过
Expression.AndAlso)比执行.Where(...).Where(...).Where(...)- 即让您的Filter<T>API 采用Dictionary<string, string>并执行循环inside,只返回一个谓词;在 C# 术语中,这是where A && B && C而不是where A where B where C -
感谢您的建议。我会相应地更新我的代码