从技术上讲,解决这个问题的正确方法是让框架接受来自 lambda 的表达式树来评估i
引用;换句话说,它是某些特定框架的 LINQ 框架限制。它目前正在尝试做的是将i
数据库解释为对它已知的某种类型(提供者)的成员访问。由于 lambda 变量捕获的工作方式,i
局部变量实际上是隐藏类上的一个字段,即提供者无法识别的具有有趣名称的字段。
所以,这是一个框架问题。
如果你真的必须通过,你可以手动构造表达式,如下所示:
ParameterExpression x = Expression.Parameter(typeof(RptCriteriaHint), "x");
var query = repo.Find(
Expression.Lambda<Func<RptCriteriaHint,bool>>(
Expression.Equal(
Expression.MakeMemberAccess(
x,
typeof(RptCriteriaHint).GetProperty("CriteriaTypeID")),
Expression.Constant(i)),
x)).ToList();
...但这只是受虐狂。
您对此条目的评论促使我进一步解释。
Lambda 可以转换为以下两种类型之一:具有正确签名的委托或具有正确签名的委托Expression<TDelegate>
。LINQ 到外部数据库(与任何类型的内存查询相反)使用第二种转换工作。
编译器将 lambda 表达式转换为表达式树,粗略地说,通过:
- 语法树由编译器解析 - 所有代码都会发生这种情况。
- 语法树在考虑变量捕获后被重写。捕获变量就像在普通委托或 lambda 中一样 - 因此会创建显示类,并将捕获的本地变量移入其中(这与 C# 2.0 匿名委托中的变量捕获行为相同)。
- 新的语法树被转换为对类的一系列调用,
Expression
以便在运行时创建一个对象树,它忠实地表示已解析的文本。
LINQ to external data sources 应该获取这个表达式树并解释它的语义内容,并将树内的符号表达式解释为引用特定于其上下文的事物(例如数据库中的列),或者要转换的立即值。通常,System.Reflection 用于查找特定于框架的属性来指导这种转换。
但是,看起来 SubSonic 没有正确处理无法找到特定领域对应关系的符号引用;而不是评估符号引用,它只是下注。因此,这是一个亚音速问题。