考虑以下代码行:
private void DoThis() { int i = 5; var repo = new ReportsRepository(); // This does NOT work var query1 = repo.Find(x => x.CriteriaTypeID == i).ToList (); // This DOES work var query1 = repo.Find(x => x.CriteriaTypeID == 5).ToList (); }
因此,当我将实际数字硬连接到lambda函数时,它工作正常.当我将捕获的变量用于表达式时,它返回时出现以下错误:
从对象类型ReportBuilder.Reporter + <> c__DisplayClass0到已知的托管提供程序本机类型不存在映射.
为什么?我该如何解决?
从技术上讲,解决这个问题的正确方法是接受lambda中的表达式树来评估i
引用的框架; 换句话说,它是某个特定框架的LINQ框架限制.它目前正在尝试做的是i
将数据库中的某个已知类型(提供者)的成员访问权限解释为.由于lambda变量捕获的工作方式,i
局部变量实际上是隐藏类的字段,具有有趣名称的字段,提供程序无法识别.
所以,这是一个框架问题.
如果你真的必须通过,你可以手动构造表达式,如下所示:
ParameterExpression x = Expression.Parameter(typeof(RptCriteriaHint), "x"); var query = repo.Find( Expression.Lambda>( Expression.Equal( Expression.MakeMemberAccess( x, typeof(RptCriteriaHint).GetProperty("CriteriaTypeID")), Expression.Constant(i)), x)).ToList();
......但这只是受虐狂.
您对此条目的评论促使我进一步解释.
Lambdas可以转换为两种类型之一:具有正确签名的委托或具有正确签名的委托Expression
.LINQ到外部数据库(与任何类型的内存中查询相对)使用第二种转换.
编译器将lambda表达式转换为表达式树,粗略地说,通过:
语法树由编译器解析 - 这适用于所有代码.
在考虑变量捕获之后重写语法树.捕获变量就像在普通委托或lambda中一样 - 因此创建显示类,并将捕获的本地移动到它们中(这与C#2.0匿名委托中的变量捕获行为相同).
新语法树被转换为对Expression
类的一系列调用,以便在运行时创建忠实地表示已解析文本的对象树.
对外部数据源的LINQ应该采用此表达式树并将其解释为其语义内容,并将树内的符号表达式解释为引用特定于其上下文的事物(例如,DB中的列)或要转换的立即值.通常,System.Reflection用于查找特定于框架的属性以指导此转换.
但是,看起来SubSonic没有正确处理它无法找到特定于域的对应关系的符号引用; 而不是评估符号引用,它只是踢.因此,这是一个SubSonic问题.