【发布时间】:2017-03-21 18:16:05
【问题描述】:
我正在 .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
);
这是我尝试一个干净的解决方案,来自控制器的路由代码。模型和视图与 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) 不会出现错误,但是当我运行它时,我得到:
运算符“Equal”的操作数与方法“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)}
【问题讨论】:
-
m.GetType().GetProperty(p).GetValue(m, null)正在返回一个对象,但q[p]正在返回一个字符串。我希望这就是问题所在。 -
@BenJaspers 我想我的问题是:
m.GetType().GetProperty(p).GetValue(m, null) // string p = "CustomString"与m.CustomString有何不同?就我而言, m.CustomString 有效,而反射方法则无效。它们是不同的类型吗? -
谷歌搜索您的错误消息表明问题可能是
m.GetType().GetProperty(p).GetValue(m, null)返回的对象是一个可为空的字符串,如果属性p是一个字符串而q[p]是不可为空的。或者我倒过来了,q[p]可以为空,而另一个不是,文档并不完全清楚。 -
基于反射的实现不能被翻译成 SQL,所以即使你修复了当前的异常,你也会得到另一个。您真正需要的是动态构建谓词表达式。一定有很多SO示例如何做类似的事情。
-
@BenJaspers - 遵循似乎这样说的 SO 问题链,看来这是 2013 年解决的错误:stackoverflow.com/questions/16797890/…
标签: c# entity-framework lambda .net-core