扩展LINQ to Entities查询的简便方法就是使用函数。有四种类型的函数可以应用:
规范函数—LINQ to Entities本身没有提供的一组预定义的函数。
数据库函数—一组预定义的SQL Server函数。
模型中定义的函数—存储在EDM中的用户定义的实体SQL函数。
自定义数据库函数—可以在查询中使用的用户定义的数据库函数。
在这部分,只涉及到规范函数和数据库函数,另外两个函数值得作出更多的解释和需要EF更深的知识,我们在11章再讨论。
规范函数是执行数据库操作的有效方法。例如,有执行数学运算,日期比较的函数等等。在EF1.0,规范函数只能在Entity SQL查询中执行,但是现在已经使用CLR方法进行了封装,如此一来就可以被LINQ to Entities调用。这一变化通过重用现有的功能扩展了LINQ to Entities的功能。
我们来看一个例子。我们的客户想要一个超过5天发货的订单列表。使用LINQ查询相当简单:
var result = from o in ctx.Orders where o.OrderDate.AddDays(5) < o.ActualShippingDate select o;
查询编译通过,但是在运行时会得到一个异常,因为翻译引擎不能将AddDays方法转换成合适SQL。
规范函数使用DiffDays方法填补这个漏洞,该方法接受两个日期作为参数,返回它们之间的天数。这个方法以及其他规范函数的的部分可以在System.Data.Objects命名空间下的EntityFunctions类中找到。
var result = from o in ctx.Orders where EntityFunctions.DiffDays(o.OrderDate, o.ActualShippingDate) > 5 select o;
另一个例子使用数学函数。四舍五入、上取整、下取整、数的n次方,所有的操作都可以使用System.Math类中的方法执行。但是,正如DateTime方法,SQL翻译引擎不支持Math中的方法。你可以使用EntityFunctions类中的Pow,Round,Ceiling和Floor作为替代方法。
这些函数可以在查询中任何位置调用而不仅仅限于where子句。例如,你可以在select子句中使用Abs函数取得一个数的绝对值。
规范函数是实体SQL与数据库无关的函数。但是在很多情况下,将你的代码指定到特定的数据库也不是问题,因为你知道你不会改变使用的数据库。如果是这种情况,你可以调用特定数据库的函数更好的使用这个平台。
每个数据库都有自己的函数集。有一些函数在不同的RDBMS中是相通的,像ABS,LTrim,RTrim,它们都可以通过LINQ to Entities或者实体函数调用。其他函数在每个数据库中都是特有的或者说有不同的特征。
幸运的是你同样也可以调用这些函数。EF在System.Data.Objects.SqlClient命名空间下的SqlFunctions类下有很多指定到SQL Server的函数。Checksum,CharIndex,Cos,GetDate和Rand都是这些有用函数的例子。
除了规范函数和数据库函数属于不同的类,它们两个没有其他的区别。它们都是作为静态方法被调用以及可以在查询的任何位置被调用。下面的代码使用数据库函数展现超过5天发货的订单。
var result = from o in ctx.Orders where SqlFunctions.DateDiff("d", o.OrderDate, o.ActualShippingDate) > 5 select o;
通过使用数据库函数,你配合你的代码到一个特定的数据库(本例子中是SQL Server)。这并不总是一个好主意,因为如果你更改数据库,就必须改变你的代码。但是如果你知道你不会改变你的应用程序使用的数据库,你可以使用数据库函数,没有任何问题。请务必慎重考虑是否应该使用这些函数。
使用特定于数据库的函数是配合你的数据库到一个数据库平台的两种方法之一。另一种选择是在代码中嵌入SQL查询。即使SQL是一种标准的语言,但查询往往依赖于特定数据库的特征,所以你最终都要将你的代码指定到特定的数据库。