`
chungle
  • 浏览: 59996 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

阅读更多

用户定义函数

我们可以在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,其代码如下:

ALTER FUNCTION [dbo].[TotalProductUnitPriceByCategory]
(@categoryID int)
RETURNS Money
AS
BEGIN
    -- Declare the return variable here
    DECLARE @ResultVar Money
    -- Add the T-SQL statements to compute the return value here
    SELECT @ResultVar = (Select SUM(UnitPrice) 
                        from Products 
                        where CategoryID = @categoryID) 
    -- Return the result of the function
    RETURN @ResultVar
END

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

[Function(Name="dbo.TotalProductUnitPriceByCategory",
IsComposable=true)]
public System.Nullable<decimal> TotalProductUnitPriceByCategory(
[Parameter(DbType="Int")] System.Nullable<int> categoryID)
{
    return ((System.Nullable<decimal>)(this.ExecuteMethodCall(this, 
    ((MethodInfo)(MethodInfo.GetCurrentMethod())), categoryID)
     .ReturnValue));
}

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

var q = from c in db.Categories
        select new
        {
            c.CategoryID,
            TotalUnitPrice =
                db.TotalProductUnitPriceByCategory(c.CategoryID)
        };

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

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

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

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

ALTER FUNCTION [dbo].[MinUnitPriceByCategory]
(@categoryID INT
)
RETURNS Money
AS
BEGIN
    -- Declare the return variable here
    DECLARE @ResultVar Money
    -- Add the T-SQL statements to compute the return value here
    SELECT @ResultVar = MIN(p.UnitPrice) FROM Products as p 
    WHERE p.CategoryID = @categoryID
    -- Return the result of the function
    RETURN @ResultVar
END

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

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

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

var q =
    from p in db.Products
    where p.UnitPrice ==
    db.MinUnitPriceByCategory(p.CategoryID)
    select p;

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

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

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

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

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

ALTER FUNCTION [dbo].[ProductsUnderThisUnitPrice]
(@price Money
)
RETURNS TABLE
AS
RETURN
    SELECT *
    FROM Products as P
    Where p.UnitPrice < @price

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

[Function(Name="dbo.ProductsUnderThisUnitPrice",
IsComposable=true)]
public IQueryable<ProductsUnderThisUnitPriceResult> 
ProductsUnderThisUnitPrice([Parameter(DbType="Money")]
System.Nullable<decimal> price)
{
    return this.CreateMethodCallQuery
    <ProductsUnderThisUnitPriceResult>(this,
    ((MethodInfo)(MethodInfo.GetCurrentMethod())), price);
}

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

private System.Nullable<bool> _Discontinued;
public System.Nullable<bool> Discontinued
{
}

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

var q = from p in db.ProductsUnderThisUnitPrice(10.25M)
        where !(p.Discontinued ?? false)
        select p;

其生成SQL语句如下:

SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], 
[t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], 
[t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel],
[t0].[Discontinued]
FROM [dbo].[ProductsUnderThisUnitPrice](@p0) AS [t0]
WHERE NOT ((COALESCE([t0].[Discontinued],@p1)) = 1)
-- @p0: Input Money (Size = 0; Prec = 19; Scale = 4) [10.25]
-- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [0]

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

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

var q =
    from c in db.Categories
    join p in db.ProductsUnderThisUnitPrice(8.50M) on
    c.CategoryID equals p.CategoryID into prods
    from p in prods
    select new
    {
        c.CategoryID,
        c.CategoryName,
        p.ProductName,
        p.UnitPrice
    };

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

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

分享到:
评论

相关推荐

    LINQ To SQL实现分页效果源码

    由于LINQ延迟执行,直到你真正遍历结果集时才会执行SQL语句。 ```csharp foreach (var customer in pagedQuery) { // 处理每个customer对象 } ``` 5. **优化性能**:在某些情况下,为了提高性能,你可能需要...

    LINQ to SQL语句(9)之Top 和Bottom和Paging和SqlMethods

    本篇文章将深入探讨LINQ to SQL语句中关于“Top”、“Bottom”、分页(Paging)以及SqlMethods的相关知识。 首先,让我们来理解“Top”和“Bottom”这两个概念。在SQL中,`TOP`用于选取结果集的前N行,而“Bottom”...

    Linq To Sql进阶系列

    - **Linq To Sql集成**:Linq To Sql支持直接调用数据库中的用户自定义函数,无需额外的SQL语句编写,进一步提高了代码的可读性和维护性。 #### 5. Linq To Sql进阶系列(五)StoreProcedure篇 ##### 存储过程与...

    LINQ to SQL语句.docx

    Where 子句是 Linq to SQL 语句中最基本的子句之一,它用于筛选数据记录。Where 子句可以使用多种形式,包括简单形式、关系条件形式和 First() 形式。 1.1 简单形式: 简单形式的 Where 子句用于筛选数据记录,...

    LINQ to SQL语句(24)之视图

    值得注意的是,由于视图是基于查询的,所以在更新或删除视图数据时,LINQ to SQL会尝试生成相应的UPDATE或DELETE SQL语句,但并非所有视图都支持这些操作。如果视图是只读的,或者由于其定义(如包含聚合函数、GROUP...

    LINQ To Sql学习文档

    LINQ To SQL 作为 LINQ 的一部分,主要用于处理关系型数据库中的数据,它能够将 SQL 查询语句转换为 .NET 语言中的对象操作。 #### 二、Visual Studio 2008 新特性及其对 LINQ 的支持 - **.NET Framework 对重定向...

    LINQ to SQL语句(14)之Null语义和DateTime

    本文将深入探讨LINQ to SQL中的一个关键主题:Null语义和DateTime处理,这对于任何进行数据库操作的开发人员来说都是至关重要的知识点。 首先,我们来谈谈Null语义。在关系数据库中,NULL值表示未知或未定义的数据...

    linq to sql 操作存储过程、函数总结(二)

    4. **性能优化**:虽然不是所有查询都比纯SQL快,但LINQ to SQL能生成高效的SQL语句。 ** LINQ to SQL 的限制 ** 1. **不支持所有SQL特性**:比如窗口函数、多表联合等复杂的SQL特性可能无法直接在LINQ中表达。 2....

    Linq to sql

    这种技术将SQL查询的语法与C#或VB.NET代码紧密集成,使得开发人员可以更方便地操作数据库,而无需编写大量的SQL语句。 **1. 查询** 在LINQ to SQL中,你可以通过实例化一个DataContext类来访问数据库中的表。例如:...

    linq to sql进阶 教程

    6. **存储过程与函数调用**:虽然LINQ主要关注直接的查询语句,但它也支持对数据库存储过程和用户定义函数的调用,这在处理复杂业务逻辑时非常有用。 7. **性能优化**:通过批处理、缓存策略和适当的数据访问模式,...

    三层架构+MVC+Linq to SQL 入门实例.rar

    它提供了强大的查询表达能力,可以方便地进行CRUD(创建、读取、更新、删除)操作,同时支持对象关系映射,减少了手动编写SQL语句的工作量。 在"Helper"文件夹中,可能包含了一些辅助类,例如日志记录、验证辅助、...

    一步一步学Linq to sql

    两者都可以实现相同的功能,但查询表达式更接近SQL语句,而方法链则类似于数据库操作的函数调用。 4. **插入、更新和删除操作**:Linq to SQL提供了简便的方法来执行CRUD(创建、读取、更新和删除)操作。只需更改...

    Linq TO Sql 扩展方法

    3. **表达式树**:在LINQ中,表达式树用于表示可执行的代码,特别是在动态查询时,它们能被解析并转换为SQL语句。 4. **动态查询**:允许在运行时构建和执行查询,这对于处理不确定的查询条件或生成复杂的动态SQL...

    linq 学习 Linq To Sql 快速入门中文教程

    Orcas引入了Lambda表达式,这是一个用于定义匿名函数的关键特性,使得在LINQ查询中创建委托更为直观和简洁。 **三、LINQ to SQL** 1. **实体模型**:LINQ to SQL提供了一个映射层,将数据库表映射到.NET类。每个...

    LINQ to SQL中文资料

    3. **动态查询转换**:当应用程序运行时,**LINQ to SQL**会自动将对象模型中的查询转换为SQL语句,并发送到数据库执行;当数据库返回结果时,它又会将这些结果转换为对象,方便开发人员进一步处理。 #### 二、LINQ...

    lINq TO sql SQL

    **LINQ to SQL** 是 .NET Framework 中的一种技术,它允许开发者使用.NET语言(如C#或VB.NET)直接对SQL数据库进行查询,无需编写大量的SQL语句。这个框架是微软在.NET 3.5 SP1版本中引入的,旨在简化数据访问层的...

    补充知识点实例(Linq To SQL)

    - **Linq To SQL工作原理**:Linq To SQL通过创建一个映射到数据库表的类,将数据库操作转化为对象操作,然后将这些对象操作转换为SQL语句执行,实现了ORM(对象关系映射)。 - **Lambda表达式**:C# 3.0引入的关键...

Global site tag (gtag.js) - Google Analytics