EDMFunction如何工作?

时间:2015-03-04 20:46:13

标签: c# entity-framework

我们有一位开发人员尝试使用字符串过滤数字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)))))

2 个答案:

答案 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();