我们有一位开发人员尝试使用字符串过滤数字ID属性:
var student = (from s in dbStudents
where s.StudentId.ToString() == "2"
select s).FirstOrDefault();
这不起作用,因为EF提供程序无法将ToString()
转换为SQL。
提供了一个解决方案,但我老实说不清楚它为什么会起作用:
[EdmFunction("SqlServer", "STR")]
public static string ConvertToString(double? number)
{
return number.HasValue ? number.ToString() : null;
}
查询现在看起来像:
var student = (from s in Students
where ConvertToString((double) s.LanguageId).Trim() == "2"
select s).FirstOrDefault();
我的理解是这个查询应该构建一个表达式树,但看起来我们在中间执行了一个CLR方法?我原以为我们只能使用提供者理解如何将其翻译成SQL的方法。
SQL看起来正确,任何人都可以告诉我我们是如何得到的:
return number.HasValue ? number.ToString() : null;
到
SELECT TOP (1)
[Extent1].[StudentId] AS [StudentId],
[Extent1].[Name] AS [Name]
FROM [dbo].[Student] AS [Extent1]
WHERE N'2' = (LTRIM(RTRIM(STR( CAST( [Extent1].[StudentId] AS float)))))
答案 0 :(得分:3)
实体框架仅使用属性中的信息将方法调用转换为SQL。在这种情况下不使用该实现。
答案 1 :(得分:3)
EdmFunction
属性在SQL中调用指定的方法。您在C#中的实现将被忽略。因此,在您的情况下,在SQL端调用STR
方法。
您可以将您的方法设为:
[EdmFunction("SqlServer", "STR")]
public static string ConvertToString(double? number)
{
throw new NotSupportedException("Direct calls not supported");
}
仍然会起作用。
请参阅:EDM and Store functions exposed in LINQ
工作原理
在LINQ中检测到具有EdmFunction属性的方法时 查询表达式,其处理方式与函数相同 在Entity-SQL查询中。使用执行过载分辨率 关于函数参数的EDM类型(不是CLR类型)。 导致模糊的过载,缺少功能或缺少过载 一个例外。另外,方法的返回类型必须是 验证。如果CLR返回类型没有隐式转换 适当的EDM类型,翻译将失败。
作为旁注,您还可以使用SqlFunctions.StringConvert
之类的:
var student = (from s in Students
where SqlFunctions.StringConvert((double) s.LanguageId)).Trim() == "2"
select s).FirstOrDefault();