演练:调试 SQL CLR 用户定义的聚合

本主题适用于:

版本

Visual Basic

C#

C++

Web Developer

学习版

主题不适用 主题不适用 主题不适用 主题不适用

标准版

主题不适用 主题不适用 主题不适用 主题不适用

专业及团队版

主题适用 主题适用 主题适用 主题适用

本示例演示如何调试 SQL Server 公共语言运行时 (SQL CLR) 用户定义的聚合。 它在**“AdventureWorks”示例数据库中创建一个新的名为“Concatenate”**的 SQL CLR 聚合函数。 当在 SQL 语句中调用此函数时,它将作为其输入参数的指定的列的所有值串联在一起。

如果在尝试调试 SQL CLR 对象时,显示消息“被用户取消”,您必须手动配置运行 Visual Studio 的计算机以及运行 SQL Server 的计算机。 有关更多信息,请参见如何:配置计算机以启用 Transact-SQL 和 SQL CLR 调试

提示

显示的对话框和菜单命令可能会与“帮助”中的描述不同,具体取决于您现用的设置或版本。 若要更改设置,请在“工具”菜单上选择“导入和导出设置”。 有关更多信息,请参见 使用设置

调试 CLR SQL 聚合函数

  1. 在一个新的 SQL CLR 项目中,建立一个到**“AdventureWorks”**示例数据库的连接。 有关更多信息,请参见How to: Connect to a Database

  2. 使用以下示例部分中第一个示例的代码创建一个新的函数,并将其命名为“Concatenate.cs”。 有关更多信息,请参见How to: Develop with the SQL Server Project Type

  3. 添加一个对该功能进行测试的脚本,方法是,在 SELECT 语句中包括该脚本。 在**“解决方案资源管理器”中右击“TestScripts”目录,选择“添加测试脚本”,然后插入本演练中第二个示例部分的代码。 以“Concatenate.sql”名称保存文件。 右击该文件名,然后单击“设置为默认调试脚本”**。

  4. 将断点放置在 Concatenate.cs 中的 Accumulate 方法内的 if 语句上。 若要执行此操作,请单击“文本编辑器”窗口左侧的灰色空白处,然后在**“调试”菜单上,单击“启动”**,对项目执行编译、部署和单元测试。 以黄色箭头表示的指令指针出现在断点上时,说明正在调试函数。

  5. 尝试各种调试功能。

    1. 对于 Concatenate.sql 中构成脚本的 GROUP BY 子句的每一行,都会执行一次 Accumulate 方法。 通过在**“调试”菜单上重复单击“逐语句”**,可监视方法结果的生成方式。

    2. 在**“局部变量”**窗口中,打开变量 value,它包含当前正处理的存储区名称。

    3. 单击变量 this。 此函数将返回子节点 intermediateResult,该节点包含到当前存储名为止的所有存储名,这些存储名连接在一起并以逗号分隔。

    4. 在文本编辑器中,双击 intermediateResult 变量以选择它。 将 intermediateResult 拖动到**“监视”**窗口,并将它放在窗口中的任意位置。 该变量随即添加到受监视的变量列表中。

    5. 逐句通过方法几次。 每次通过该方法时,intermediateResult 的值都将更改,并在结尾处连接另外一个存储名。

    6. 单击断点以将其移除,然后向 Terminate 方法内的第一个语句添加断点。 此方法将结果返回给调用方。 若要单步执行它,请在**“调试”菜单上,单击“启动”。 现在可以通过单击“调试”菜单上的“单步执行”**来逐句通过它。 在遇到 return 语句时停止。

    7. 再次单击**“继续”**完成函数调试。

示例

下面是本示例中使用的聚合函数的代码。

using System;
using System.Data.Sql;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Text;
[Serializable]
[SqlUserDefinedAggregate( 
    //use CLR serialization to serialize the intermediate result. 
    Format.UserDefined, 
    //Optimizer property: 
    IsInvariantToNulls=true,
    //Optimizer property: 
    IsInvariantToDuplicates=false,
    //Optimizer property: 
    IsInvariantToOrder=false,
    //Maximum size in bytes of persisted value: 
    MaxByteSize=8000)
] 
public class Concatenate: IBinarySerialize 
{ 
    /// <summary> 
    /// Variable holds intermediate result of the concatenation 
    /// </summary> 
    private StringBuilder intermediateResult; 
    /// <summary> 
    /// Initialize the internal data structures 
    /// </summary> 
    public void Init( ) 
    { 
        intermediateResult = new StringBuilder(); 
    } 
    /// <summary> 
    /// Accumulate the next value, nop if the value is null 
    /// </summary> 
    /// <param name="value"></param> 
    public void Accumulate(SqlString value) 
    { 
        if(value.IsNull) 
        { 
            return; 
        } 
        intermediateResult.Append(value.Value).Append(','); 
    } 
    /// <summary> 
    /// Merge the partially computed aggregate with this aggregate. 
    /// </summary> 
    /// <param name="other"></param> 
    public void Merge( Concatenate other) 
    { 
        intermediateResult.Append(other.intermediateResult); 
    } 
    /// <summary> 
    /// Called at end of aggregation, to return results. 
    /// </summary> 
    /// <returns></returns> 
    public SqlString Terminate() 
    { 
        string output = string.Empty; 
        //Delete the trailing comma, if any .
        if (intermediateResult != null && intermediateResult.Length > 0) 
            output = intermediateResult.ToString(0, intermediateResult.Length-1); 
        return new SqlString(output); 
    } 
    public void Read(BinaryReader r) 
    { 
        intermediateResult = new StringBuilder(r.ReadString()); 
    } 
    public void Write(BinaryWriter w) 
    { 
        w.Write(intermediateResult.ToString()); 
    } 
}

这是调用此函数的测试脚本。

SELECT scu.SalesPersonID, dbo.Concatenate(sst.Name)
FROM Sales.Customer as scu 
INNER JOIN Sales.Store as sst
    ON scu.CustomerID    = sst.CustomerID
INNER JOIN Sales.SalesPerson as spr
    ON scu.SalesPersonID = spr.SalesPersonID
WHERE    scu.SalesPersonID = 283
GROUP BY scu.SalesPersonID

请参见

任务

如何:通过使用公共语言运行时集成创建和运行 SQL Server 聚合