我正在 .NET Core 中构建 MVC API。我有几个非常大的表(第 3 方系统),我试图允许将任何列的名称作为 URL 参数传递,并在 Where 子句中使用一个值。这使用 Entity Framework 和 .NET Core。
想法是抓取与参数名称匹配的列,并在带有参数值的 Where 子句中使用它。我希望 Where 查询中的 lambda 最终看起来像:
//GET: api/DWRWorkItems?Parameter=Value
...
dWRWorkItem = dWRWorkItem.Where(m =>
m.Parameter == Value
);
这是我尝试的一个干净的解决方案,来自 Controller 的路由代码。模型和 View 与 Entity Framework 创建的默认值没有变化。
// GET: api/DWRWorkItems
[HttpGet]
public IEnumerable<DWRWorkItem> GetTDwrWrkItm()
{
IQueryable<DWRWorkItem> dWRWorkItem = _context.TDwrWrkItm.Where(m => 1 == 1);
var q = HttpContext.Request.Query;
foreach (string p in q.Keys)
{
dWRWorkItem = dWRWorkItem.Where(m =>
m.GetType().GetProperty(p).GetValue(m, null) == q[p]
);
}
return dWRWorkItem.ToList();
}
Intellisense (VS 2017) 预计不会出现错误,但是当我运行它时,我得到:
The operands for operator 'Equal' do not match the parameters of method 'op_Equality'.
单步执行代码,lambda 中的反射似乎没有按预期工作。这是 dWRWorkItem.Expression.Arguments[1] 的样子:
{m => (GetProperty(m.GetType(), value(EBOOKS.Controllers.DWRWorkItemsController+<>c__DisplayClass0#1).p).GetValue(m, null) == value(EBOOKS.Controllers.DWRWorkItemsController+<>c__DisplayClass0#1).CS$<>8__locals1.q.get_Item(value(EBOOKS.Controllers.DWRWorkItemsController+<>c__DisplayClass0#1).p))}
虽然参数不是动态的示例如下所示:
{m => (m.ContId == value(EBOOKS.Controllers.DWRWorkItemsController+<>c__DisplayClass3_0).id)}
最佳答案
一般来说,除 LINQ to Objects 之外的查询提供程序不喜欢表达式树内部的反射调用,因此最好使用 System.Linq.Expressions.Expression
动态组合表达式类方法。
这是适合您的情况的自定义扩展方法:
public static partial class QueryableExtensions
{
public static IQueryable<T> WhereEquals<T>(this IQueryable<T> source, string memberPath, string value)
{
var parameter = Expression.Parameter(typeof(T), "e");
var left = memberPath.Split('.').Aggregate((Expression)parameter, Expression.PropertyOrField);
var right = Expression.Constant(ToType(value, left.Type), left.Type);
var predicate = Expression.Lambda<Func<T, bool>>(Expression.Equal(left, right), parameter);
return source.Where(predicate);
}
private static object ToType(string value, Type type)
{
if (type == typeof(string)) return value;
if (string.IsNullOrEmpty(value)) return null;
return Convert.ChangeType(value, Nullable.GetUnderlyingType(type) ?? type);
}
}
除了使用 Expression.Equal
(相当于 ==
运算符)之外,它还必须将 string
处理为实际值类型转换,顺便说一句,这是你原来的异常的原因。
用法是这样的:
var dWRWorkItem = _context.TDwrWrkItm.AsQueryable();
var q = HttpContext.Request.Query;
foreach (string p in q.Keys)
dWRWorkItem = dWRWorkItem.WhereEquals(p, q[p]);
return dWRWorkItem.ToList();
关于c# - 进行通用 MVC API 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42935150/