c# - 可查询的高级 where 的扩展方法
问题描述
我正在尝试添加扩展方法IQueryable<T>
,以便将特定的位置附加到IQueryable
.
假设用户正在搜索名称等于的数据"Matt"
public IEnumerable<Employees> Search(String name)
{
var qList = _context.Employees;
if(!String.isNullOrEmpty(name))
qList = qList.Where(emp => emp.Name == name);
return qList.ToList();
}
现在,如果用户正在搜索名称以"Matt"
- 开头的数据,他可能会尝试在特定的文本框中写一些"Matt%**"
东西。"Matt*"
为了预测这一点,我可以做到:
public IEnumerable<Employees> Search(String name)
{
var qList = _context.Employees;
if(!String.isNullOrEmpty(name))
{
string extractedName = name.Replace("%","").Replace("*","");
if(name.EndsWith("%") || name.EndsWith("*");
qList = qList.Where(emp => emp.Name.StartsWith(extractedName));
}
return qList.ToList();
}
很多 IF 语句将在这里预测所有可能性,但没关系。我能做到。但我不喜欢每次执行此类功能时都重复我的代码。
我如何制作扩展方法
IQueryable<T>
哪个会一直为我做这个检查?
public static IQueryable<T> MyAdvancedSearch<T>(this IQueryable<T> qList, String searchText)
{
if(!String.isNullOrEmpty(searchText))
/// ... Problem starts here.. because I cannot make this "Where":
qList.Where(prop=>prop.??? == searchText);
/// ... I dont know how to tell my method which field should be filtered
}
更新 我设法创建了一个看起来不错的扩展方法:
public static IQueryable<T> Filter<T>(this IQueryable<T> qList, Func<T,string> property, string text )
{
if (!String.IsNullOrEmpty(text))
{
if ((text.StartsWith("%") || text.StartsWith("*")) && (text.EndsWith("*") || text.EndsWith("*")))
qList = qList.Where(e => property(e).Contains(text));
else if (text.StartsWith("%") || text.StartsWith("*"))
qList = qList.Where(e => property(e).EndsWith(text));
else if (text.EndsWith("%") || text.EndsWith("*"))
qList = qList.Where(e => property(e).StartsWith(text));
else
qList = qList.Where(e => property(e) == text);
}
return qList;
}
但是当我尝试做 qList.Tolist() 我收到错误:
InvalidOperationException: The LINQ expression 'DbSet<Employee>()
.Where(o => Invoke(__property_0, o)
== __text_1)' could not be translated.
InvalidOperationException: The LINQ expression 'DbSet<Employee>() .Where(o => Invoke(__property_0, o) == __text_1)'
could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
解决方案
这应该可以解决问题
public static IQueryable<T> MyAdvancedSearch<T>(this IQueryable<T> qList, Expression<Func<T, string>> property, String text)
{
Expression<Func<T, bool>> expression = null;
var propertyName = GetPropertyName(property);
var parameter = Expression.Parameter(typeof(T), "x");
var left = propertyName.Split('.').Aggregate((Expression)parameter, Expression.Property);
var right = Expression.Constant(text, typeof(string));
Expression body = null;
if (!string.IsNullOrEmpty(text))
{
if ((text.StartsWith("%") || text.StartsWith("*")) && (text.EndsWith("%") || text.EndsWith("*")))
body = Expression.Call(left, "Contains", Type.EmptyTypes, Expression.Constant(text, typeof(string)));
else if (text.StartsWith("%") || text.StartsWith("*"))
body = Expression.Call(left, "EndsWith", Type.EmptyTypes, Expression.Constant(text, typeof(string)));
else if (text.EndsWith("%") || text.EndsWith("*"))
body = Expression.Call(left, "StartsWith", Type.EmptyTypes, Expression.Constant(text, typeof(string)));
else
body = Expression.MakeBinary(ExpressionType.Equal, left, right);
}
expression = Expression.Lambda<Func<T, bool>>(body, parameter);
qList = qList.Where(expression);
return qList;
}
public static string GetPropertyName<TClass, TProperty>(Expression<Func<TClass, TProperty>> property)
{
MemberExpression member = property.Body as MemberExpression;
PropertyInfo info = member.Member as PropertyInfo;
return info.Name;
}
public static IQueryable<T> MyAdvancedSearch<T>(this IQueryable<T> qList, Func<T, string> func, String searchText)
{
qList.Where(prop => func(prop) == searchText);
return qList;
}
var qList = _context.Employees.MyAdvancedSearch((emp) => emp.Name, extractedname)
推荐阅读
- python - 如何在 Windows 上将 JSON 字符串传递给 Python 程序的命令行?
- c++ - 制作迭代器的副本是不是一个坏主意?
- javascript - html5画布drawImage缩放使结果模糊
- javascript - Vue - 在 v-for 循环中将 v-model 从子级传递给父级
- javascript - 使用响应 HTTP 重定向的 URL 预加载/缓存图像
- css - 使用 css 网格的垂直和水平居中的 4x4 方形网格
- git - 为什么没有自动生成master分支?
- angular - 对于自定义表单组件,是否可以使用 DefaultValueAccessor 而不是 ControlValueAccessor?
- c# - 如何在不使用 asp.net mvc 中的模型类的情况下从视图下拉列表中获取数据到控制器
- vuejs2 - Vue 组件 prop 更改不会触发重新渲染