LINQ to SQL语句(21)之用户定义函数

30 篇文章 0 订阅

http://www.prg-cn.com/article-4433-1.html

用户定义函数

我们可以在LINQ to SQL中使用用户定义函数。只要把 用户定义函数拖到O/R设计器中,LINQ to SQL自动使用FunctionAttribute属性 和ParameterAttribute属性(如果需要)将其函数指定为方法。这时,我们只需 简单调用即可。

在这里注意:使用用户定义函数的时候必须满足以下形 式之一,否则会出现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));
  9. }
复制代码

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

  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));
  8. }
复制代码

这时可以使用了:注意这 里在 LINQ to SQL 查询中,对生成的用户定义函数方法 MinUnitPriceByCategory的内联调用。此函数不会立即执行,这是因为查询会延 迟执行。延迟执行的查询中包含的函数直到此查询执行时才会执行。为此查询生 成的 SQL 会转换成对数据库中用户定义函数的调用(请参见此查询后面的生成 的 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])
复制代码

3.使用用户定义的表值函数

表值函数返回单个行集(与 存储过程不同,存储过程可返回多个结果形状)。由于表值函数的返回类型为 Table,因此在 SQL 中可以使用表的任何地方均可以使用表值函数。此外,您还 可以完全像处理表那样来处理表值函数。

下面的 SQL 用户定义函数显式 声明其返回一个 TABLE。因此,隐式定义了所返回的行集结构。

  1. ALTER FUNCTION [dbo].[ProductsUnderThisUnitPrice]
  2. (@price Money
  3. )
  4. RETURNS TABLE
  5. AS
  6. RETURN
  7.   SELECT *
  8.    FROM Products as P
  9.   Where p.UnitPrice < @price
复制代码

拖到设计器中,LINQ to SQL 按如下方式映射此函数:

  1. [Function (Name="dbo.ProductsUnderThisUnitPrice",
  2. IsComposable=true)]
  3. public IQueryable<ProductsUnderThisUnitPriceResult>
  4. ProductsUnderThisUnitPrice([Parameter(DbType="Money")]
  5. System.Nullable<decimal> price)
  6. {
  7.   return this.CreateMethodCallQuery
  8.    <ProductsUnderThisUnitPriceResult>(this,
  9.   ((MethodInfo) (MethodInfo.GetCurrentMethod())), price);
  10. }
复制代码

这时我们 小小的修改一下Discontinued属性为可空的bool类型。

  1. private System.Nullable<bool> _Discontinued;
  2. public System.Nullable<bool> Discontinued
  3. {
  4. }
复制代码

我 们可以这样调用使用了:

  1. var q = from p in db.ProductsUnderThisUnitPrice(10.25M)
  2.     where ! (p.Discontinued ?? false)
  3.     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]
  5. FROM [dbo]. [ProductsUnderThisUnitPrice](@p0) AS [t0]
  6. WHERE NOT ((COALESCE ([t0].[Discontinued],@p1)) = 1)
  7. -- @p0: Input Money (Size = 0; Prec = 19; Scale = 4) [10.25]
  8. -- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [0]
复制代码

4.以联接方式使用用户定义的表值函数

我们 利用上面的ProductsUnderThisUnitPrice用户定义函数,在 LINQ to SQL 中, 调用如下:

  1. var q =
  2.   from c in db.Categories
  3.   join p in db.ProductsUnderThisUnitPrice(8.50M) on
  4.    c.CategoryID equals p.CategoryID into prods
  5.   from p in prods
  6.   select new
  7.   {
  8.     c.CategoryID,
  9.     c.CategoryName,
  10.     p.ProductName,
  11.      p.UnitPrice
  12.   };
复制代码

其生成的 SQL 代码说明对此函数返回 的表执行联接。

  1. SELECT [t0].[CategoryID], [t0]. [CategoryName],
  2. [t1].[ProductName], [t1].[UnitPrice]
  3. FROM [dbo].[Categories] AS [t0]
  4. CROSS JOIN [dbo]. [ProductsUnderThisUnitPrice](@p0) AS [t1]
  5. WHERE ([t0]. [CategoryID]) = [t1].[CategoryID]
  6. -- @p0: Input Money (Size = 0; Prec = 19; Scale = 4) [8.50]
复制代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值