Linq用户定义函数剖析

开发 后端
这里介绍Linq用户定义函数,这里在 LINQ to SQL 查询中,对生成的Linq用户定义函数方法MinUnitPriceByCategory的内联调用。

学习Linq用户定义函数时,经常会遇到Linq用户定义函数问题,这里将介绍XX问题的解决方法。

Linq用户定义函数

我们可以在LINQ to SQL中使用Linq用户定义函数。只要把Linq用户定义函数拖到O/R设计器中,LINQ to SQL自动使用FunctionAttribute属性和ParameterAttribute属性(如果需要)将其函数指定为方法。这时,我们只需简单调用即可。
在这里注意:使用Linq用户定义函数的时候必须满足以下形式之一,否则会出现InvalidOperationException异常情况。
◆具有正确映射属性的方法调用的函数。这里使用FunctionAttribute属性和 ParameterAttribute属性。
◆特定于LINQ to SQL的静态SQL方法。
◆.NET Framework方法支持的函数。

下面介绍几个例子:

1.在Select中使用用户定义的标量函数

所谓标量函数是指返回在 RETURNS 子句中定义的类型的单个数据值。可以使用所有标量数据类型,包括 bigint 和 sql_variant。不支持 timestamp 数据类型、用户定义数据类型和非标量类型(如 table 或 cursor)。在 BEGIN...END 块中定义的函数主体包含返回该值的 Transact-SQL 语句系列。返回类型可以是除 text、ntext、image、cursor 和 timestamp 之外的任何数据类型。我们在系统自带的NORTHWND.MDF数据库中,有3个自定义函数,这里使用TotalProductUnitPriceByCategory,其代码如下:

  1. ALTER FUNCTION [dbo].[TotalProductUnitPriceByCategory]  
  2. (@categoryID int)  
  3. RETURNS Money  
  4. AS  
  5. BEGIN  
  6. -- Declare the return variable here  
  7. DECLARE @ResultVar Money  
  8. -- Add the T-SQL statements to compute the return value here  
  9. SELECT @ResultVar = (Select SUM(UnitPrice)   
  10. from Products   
  11. where CategoryID = @categoryID)   
  12. -- Return the result of the function  
  13. RETURN @ResultVar  
  14. END 

我们将其拖到设计器中,LINQ to SQL通过使用 FunctionAttribute 属性将类中定义的客户端方法映射到用户定义的函数。请注意,这个方法体会构造一个捕获方法调用意向的表达式,并将该表达式传递给 DataContext 进行转换和执行。

  1. [Function(Name="dbo.TotalProductUnitPriceByCategory",  
  2. IsComposable=true)]  
  3. public System.Nullable<decimal> TotalProductUnitPriceByCategory(  
  4. [Parameter(DbType="Int")] System.Nullable<int> categoryID)  
  5. {  
  6. return ((System.Nullable<decimal>)(this.ExecuteMethodCall(this,   
  7. ((MethodInfo)(MethodInfo.GetCurrentMethod())), categoryID)  
  8. .ReturnValue));  

我们使用时,可以用以下代码来调用:

  1. var q = from c in db.Categories  
  2. select new  
  3. {  
  4. c.CategoryID,  
  5. TotalUnitPrice =  
  6. db.TotalProductUnitPriceByCategory(c.CategoryID)  
  7. }; 

这时,LINQ to SQL自动生成SQL语句如下:

  1. SELECT [t0].[CategoryID], CONVERT(Decimal(29,4),  
  2. [dbo].[TotalProductUnitPriceByCategory]([t0].[CategoryID]))  
  3. AS [TotalUnitPrice] FROM [dbo].[Categories] AS [t0] 

2.在Where从句中使用用户定义的标量函数

这个例子使用方法同上一个例子原理基本相同了,MinUnitPriceByCategory自定义函数如下:

  1. ALTER FUNCTION [dbo].[MinUnitPriceByCategory]  
  2. (@categoryID INT  
  3. )  
  4. RETURNS Money  
  5. AS  
  6. BEGIN  
  7. -- Declare the return variable here  
  8. DECLARE @ResultVar Money  
  9. -- Add the T-SQL statements to compute the return value here  
  10. SELECT @ResultVar = MIN(p.UnitPrice) FROM Products as p   
  11. WHERE p.CategoryID = @categoryID  
  12. -- Return the result of the function  
  13. RETURN @ResultVar  
  14. END 

拖到设计器中,生成代码如下:

  1. [Function(Name="dbo.MinUnitPriceByCategory"IsComposable=true)]  
  2. public System.Nullable<decimal> MinUnitPriceByCategory(  
  3. [Parameter(DbType="Int")] System.Nullable<int> categoryID)  
  4. {  
  5. return ((System.Nullable<decimal>)(this.ExecuteMethodCall(  
  6. this, ((MethodInfo)(MethodInfo.GetCurrentMethod())),  
  7. categoryID).ReturnValue));  

这时可以使用了:注意这里在 LINQ to SQL 查询中,对生成的Linq用户定义函数方法MinUnitPriceByCategory的内联调用。此函数不会立即执行,这是因为查询会延迟执行。延迟执行的查询中包含的函数直到此查询执行时才会执行。为此查询生成的 SQL 会转换成对数据库中Linq用户定义函数的调用(请参见此查询后面的生成的 SQL语句),当在查询外部调用这个函数时,LINQ to SQL 会用方法调用表达式创建一个简单查询并执行。

  1. var q =  
  2. from p in db.Products  
  3. where p.UnitPrice ==  
  4. db.MinUnitPriceByCategory(p.CategoryID)  
  5. select p; 

它自动生成的SQL语句如下:

  1. SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID],  
  2. [t0].[CategoryID],[t0].[QuantityPerUnit], [t0].[UnitPrice],  
  3. [t0].[UnitsInStock], [t0].[UnitsOnOrder],[t0].[ReorderLevel],  
  4. [t0].[Discontinued]FROM [dbo].[Products] AS [t0]  
  5. WHERE [t0].[UnitPrice] =   
  6. [dbo].[MinUnitPriceByCategory]([t0].[CategoryID]) 

【编辑推荐】

  1. Linq结果集形状概述
  2. Linq存储过程返回详解
  3. Linq调用LoadProducts方法
  4. Linq使用数据表简单描述
  5. Linq对象引用简单介绍
责任编辑:佚名 来源: IT168
相关推荐

2009-09-09 14:40:43

Linq to sql

2009-09-09 16:21:31

Linq使用sqlme

2009-09-14 10:13:02

LINQ查询操作

2009-09-14 15:12:40

LINQ to XML

2009-09-17 13:15:20

LINQ查询

2009-09-10 14:37:57

LINQ匿名类型

2009-09-16 16:59:05

LINQ to XML

2009-09-16 09:56:42

LINQ to SQL

2009-09-17 09:20:34

Linq和dLinq区

2009-09-08 16:20:12

LINQ to SQL

2009-09-18 17:17:58

LINQ模型

2009-09-08 15:39:13

Linq使用Inser

2009-09-15 14:52:15

linq级联删除

2009-09-14 10:35:15

Linq内部执行原理

2009-09-11 09:48:27

Linq Lambda

2009-09-17 15:22:38

LINQ to SQL

2009-09-10 15:35:07

LINQ查询表达式

2009-09-07 16:25:14

Linq To SQL

2009-09-07 21:25:59

Linq自定义

2009-09-08 09:59:26

LINQ遍历多个数组
点赞
收藏

51CTO技术栈公众号