我正在努力实现以下模式:
Main()
{
...
GetFilteredUsersById(u => u >= 100 && u < 200).Dump();
....
}
public List<UserRecord> FilteredUsersById(Func<int, bool> filter)
{
Expression<Func<UserRecord, bool>> filterExpression = x => filter(x.Id);
return someUserRecordsDb.Where(filterExpression).ToList();
}
public class UserRecord
{
public int Id;
public string Name;
}
当然,这会失败
NotSupportedException:Method&#39; System.Object DynamicInvoke(System.Object [])&#39;没有受支持的SQL翻译。
我理解错误发生的原因,但不知道如何修复错误。
下面是一个可行的模式,但我有兴趣了解我需要对上面第一个模式的代码进行哪些更改才能使其正常工作。
Main()
{
...
GetFilteredUsersById(u => u.Id >= 100 && u.Id < 200).Dump();
....
}
public List<UserRecord> FilteredUsers(Expression<Func<UserRecord, bool>> filter)
{
return someUserRecordsDb.Where(filter).ToList();
}
public class UserRecord
{
public int Id;
public string Name;
}
感谢您在StackOverflow上回答我的第一个问题!
答案 0 :(得分:0)
正如您所知,LINQ to SQL的工作方式是将您的lambda作为表达式树而不是委托。然后,它分析这些树并尝试生成等效的SQL代码。显然,它无法支持您可以用C#编写的所有内容。
在第二个代码段中,LINQ提供程序会看到一个包含以下内容的表达式树:
u => u.Id >= 100 && u.Id < 200
这很容易理解 - 它涉及&&
运算符,>=
运算符和<
运算符,所有这些都是已知的。
但是在你的第一个片段中,LINQ提供程序会看到一个包含它的表达式树:
x => filter(x.Id)
这是非常不同的,因为它是对提供者不知道的任意方法的调用。所以现在提供者必须查看该方法并查看它包含的内容。如果该方法具有另一级别的间接,则提供者必须进一步查看。等等。
如果您的表达式树需要这种工作,提供者将拒绝这样做。因此,对任意方法的任何调用都将失败。
因此,答案很简单:不要在创建表达式树的位置和要转换为SQL的实际表达式之间放置一个间接级别,否则LINQ提供程序将完全拒绝它。
答案 1 :(得分:0)
这里要记住两件事
<强> 1。 Expression vs Func
您需要了解的主要内容之一是Expression
和Func
或任何类型的委托类型之间的区别。简而言之,表达式传递了lamda的树表示,可以将其转换为Sql。
这里有一个很好的答案,深入探讨这个问题: Why would you use Expression<Func<T>> rather than Func<T>?
<强> 2。并非所有表达式都适用于Linq-to-Sql
即使函数可以表示为表达式,也不意味着正在使用正在使用linq表达式的提供程序的lambda表达式中执行的操作的正确映射。
这就是你得到例外的原因:
NotSupportedException:Method&#39; System.Object DynamicInvoke(System.Object [])&#39;没有受支持的SQL翻译。
这里即使它是一个有效的表达式,也无法将操作转换为sql ,这就是为什么你得到一个异常,即使filter
是一个有效的lambda如果通过作为一个表达式并直接调用该语句的翻译是它试图调用这个函数filter
,它不会直接映射到sql中的任何内容