我想创建一个通用服务,该服务仅通过其修饰的属性(通过自定义属性)在特定实体中进行搜索,而我尝试使用表达式来执行此操作,但我想我缺少了一些东西。这里是一个示例代码:
服务
public class MyService<TEntity>
where TEntity: class
{
private readonly MyContext context;
public MyService()
{
this.context = new MyContext();
}
private Func<TEntity, string, bool> searchFunc = (e, search) =>
{
var type = typeof(TEntity);
var props = type.GetProperties().Where(p => p.GetCustomAttributes(typeof(SearchPropertyAttribute), true).Any());
Expression expression = Expression.Constant(false);
foreach (var prop in props)
{
expression = Expression.MakeBinary(ExpressionType.Or,
expression,
Expression.MakeBinary(ExpressionType.Equal,
Expression.Property(Expression.Constant(e), prop.Name),
Expression.Constant(search)));
}
var delegateFunc = Expression.Lambda<Func<TEntity, string, bool>>(expression).Compile();
return delegateFunc(e, search);
};
/// <summary>
/// searches in specified entity set the given string using only decorated properties.
/// </summary>
public List<TEntity> Find(string search)
{
var list = this.context.Set<TEntity>().Where(e => searchFunc(e as TEntity, search));
return list.ToList() as List<TEntity>;
}
}
实体
public class MyEntity
{
[SearchProperty]
public string FirstName { get; set; }
[SearchProperty]
public string LastName { get; set; }
public string Description { get; set; }
}
我只想限制由SearchProperty属性装饰的属性的搜索谢谢
我已经在最近的项目中实现了该功能,并为此在基本控制器中创建了以下方法:
获取实体的可过滤道具:
private List<PropertyInfo> GetFilterProps()
{
var t = typeof(TEntity);
var props = t.GetProperties();
var filterProps = new List<PropertyInfo>();
foreach (var prop in props)
{
var attr = (SearchProperty[])prop.GetCustomAttributes(typeof(SearchProperty), false);
if (attr.Length > 0)
{
filterProps.Add(prop);
}
}
return filterProps;
}
使用表达式树生成动态查询:
private IQueryable<TEntity> Filter(IQueryable<TEntity> query, string value)
{
if (string.IsNullOrEmpty(value) || this.filterProps.Count == 0) return query;
ConstantExpression constant = Expression.Constant(value.ToLower());
ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "e");
MemberExpression[] members = new MemberExpression[filterProps.Count()];
MethodInfo containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
MethodInfo toLowerMethod = typeof(string).GetMethod("ToLower", System.Type.EmptyTypes);
for (int i = 0; i < filterProps.Count(); i++)
{
members[i] = Expression.Property(parameter, filterProps[i]);
}
Expression predicate = null;
foreach (var member in members)
{
//e => e.Member != null
BinaryExpression notNullExp = Expression.NotEqual(member, Expression.Constant(null));
//e => e.Member.ToLower()
MethodCallExpression toLowerExp = Expression.Call(member, toLowerMethod);
//e => e.Member.Contains(value)
MethodCallExpression containsExp = Expression.Call(toLowerExp, containsMethod, constant);
//e => e.Member != null && e.Member.Contains(value)
BinaryExpression filterExpression = Expression.AndAlso(notNullExp, containsExp);
predicate = predicate == null ? (Expression)filterExpression : Expression.OrElse(predicate, filterExpression);
}
var lambda = Expression.Lambda<Func<TEntity, bool>>(predicate, parameter);
return query.Where(lambda);
}
在您的Get方法中,您将获得类似以下内容的信息:
[HttpGet]
public virtual async Task<IActionResult> List([FromQuery] string filter)
{
var query = _context.Set<TEntity>();
query = Filter(query, filter);
var result = await query.ToListAsync();
return Ok(result);
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句