zoukankan      html  css  js  c++  java
  • SQL SERVER 2005 CLR 部署UDT,Triggers,Functions,Procedure,Aggregates

    作者tag:c# sql server 微软 microsoft windows/.net procedure functions aggregates sql server 2005 clr 部署udt,triggers 
    ◆[CLR User-Defined Types]
     
    ●>  A Simple Example: The PhoneNumber Type
     
    --Example in 第 201/705 页
     
    Another important thing to remember is that methods and properties on user-defined types are case sensitive, even if the server or database isn’t.
    (大小写敏感,存储过程也是这样)
     
    ●>  Another Example: The StringArray Type
     
    ●>  Wrapping the Functionality of a Generic List

    Generics solve this problem by allowing developers to specify a type to be used by a class (or collection) at object creation time.
     
    ●>  Complete StringArray Class Sample
     
    --Complete StringArray Class Sample 代码:第 208/705 页
     
    ●>  Using the StringArray
     
    --T-SQL中:
    DECLARE @array StringArray
    SET @array = 'a,b,c'
     
    --与上句一样的功能:
    DECLARE @array StringArray
    SET @array = @array.AddString('a')
    SET @array = @array.AddString('b')
    SET @array = @array.AddString('c')
     
    ●>  Managing User-Defined Types
     
    --If an assembly has been loaded into the database using CREATE ASSEMBLY,
    --The following code creates the StringArray type from an assembly called StringArray:
    Create Type StringArray
    External Name StringArray.StringArray
     
    --The following code drops the StringArray type:
    DROP TYPE StringArray
     
    --To enumerate the data for CLR user-defined type in the database:
    SELECT * FROM sys.types
    WHERE is_assembly_type = 1
     
     
    ◆[CLR User-Defined Functions]
    If a T-SQL user-defined function can do the job in question, T-SQL is preferred—most of the time it will deliver better performance and quicker development turnaround.
     
    ●>  Binary Data Compression Using a Scalar User-Defined Function

    using System.IO;
    using System.IO.Compression;
     
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlBytes BinaryCompress(SqlBytes inputStream) //加密
    {
        using (MemoryStream ms = new MemoryStream())
        {
            using (GZipStream x =
            new GZipStream(ms, CompressionMode.Compress, true))
            {
                byte[] inputBytes = (byte[])inputStream.Value;
                x.Write(inputBytes, 0, inputBytes.Length);
            }
            return (new SqlBytes(ms.ToArray()));
        }
    }
     
     
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlBytes BinaryDecompress(SqlBytes inputBinary) //解密
    {
        byte[] inputBytes = (byte[])inputBinary.Value;
        using (MemoryStream memStreamIn = new MemoryStream(inputBytes))
        {
            using (GZipStream s =
            new GZipStream(memStreamIn, CompressionMode.Decompress))
            {
                using (MemoryStream memStreamOut = new MemoryStream())
                {
                    for (int num = s.ReadByte(); num != -1; num = s.ReadByte())
                    {
                        memStreamOut.WriteByte((byte)num);
                    }
                    return (new SqlBytes(memStreamOut.ToArray()));
                }
            }
        }
    }
     
     
    ●>  Using the Compression Routines
     
    --大概有50%的压缩率:
    Select DataLength(Document),DataLength(dbo.BinaryCompress(Document))
    From Production.Document
    where DocumentID = 1
     
    --注意:压缩图片字段时,反而会变大:
    SELECT DATALENGTH(LargePhoto),DATALENGTH(dbo.BinaryCompress(LargePhoto))
    FROM Production.ProductPhoto
    where ProductPhotoID = 1
     

    ●>  Table-Valued User-Defined Functions

    --Example in 第 219/705 页
    --This process is better described using a concrete example. Assume that you
    --wish to encapsulate the following query in a user-defined function:
    SELECT Name, GroupName FROM HumanResources.Department
     
    --VS2005:
    using System.Collections;
     
    //The following code defines a method called GetDepartments that retrieves
    //and returns the data using a context connection:
    [Microsoft.SqlServer.Server.SqlFunction(
    DataAccess = DataAccessKind.Read,
    FillRowMethodName = "GetNextDepartment",
    TableDefinition = "Name NVARCHAR(50), GroupName NVARCHAR(50)")]
    public static IEnumerable GetDepartments()
    {
        using (SqlConnection conn =
        new SqlConnection("context connection=true;"))
        {
            string sql ="SELECT Name, GroupName FROM HumanResources.Department";
            conn.Open();
            SqlCommand comm = new SqlCommand(sql, conn);
            SqlDataAdapter adapter = new SqlDataAdapter(comm);
            DataSet dSet = new DataSet();
            adapter.Fill(dSet);
            return (dSet.Tables[0].Rows);
        }
    }
     
    //The method must have a single input parameter of type object,
    //followed by an output parameter for each column defined in the TableDefinition parameter.
    public static void GetNextDepartment(object row,out string name,out string groupName)
    {
        DataRow theRow = (DataRow)row;
        name = (string)theRow["Name"];
        groupName = (string)theRow["GroupName"];
    }
     
    /*
    The SQL Server engine will call MoveNext (one of the methods defined in the IEnumerator interface, which is required by IEnumerable) on the DataTable for each row of
    output. Each call to MoveNext will return an instance of a DataRow, which will then be passed to the GetNextDepartment function. Finally, that function will map the data in the row to the proper output
    parameters, which will become the columns in the output table.
    */
     
    --SQL2005中调用:
    select * from dbo.GetDepartments()
     
     
    ●>  References in CLR Projects: Splitting the StringArray into a Table

    To reference a third-party assembly within another assembly to be loaded within a SQL Server 2005 database, the third-party assembly must first be loaded using CREATE ASSEMBLY.

    --Example in 第 220/705 页
     
    ●>  Managing CLR User-Defined Functions
    If an assembly has been loaded into the database using CREATE ASSEMBLY, functions can be created or dropped :
     
    --T-SQL:
    Create Function [dbo].[BinaryCompress](@inputStream [varbinary](max))
    RETURNS [varbinary](max) WITH EXECUTE AS CALLER
    AS
    EXTERNAL NAME [UserDefinedFunctions].[UserDefinedFunctions].[BinaryCompress]
    GO
     
    Drop Function [dbo].[BinaryCompress]
     
    --Although there is no dedicated view for user-defined functions,
    --they can be enumerated using the sys.objects catalog view.
    Select * From sys.objects WHERE type in ('FS', 'FT')
     

    ◆[CLR User-Defined Aggregates]
     
    ●>  Adding a User-Defined Aggregate to a SQL Server Project
    Programming a user-defined aggregate is in many ways similar to programming user-defined types.
    It is important to understand when dealing with aggregates that the intermediate result will be serialized and deserialized once per row of aggregated data.
     
    ●>  Programming the TrimmedMean Aggregate
    --Example Code in 第 227/705 页
     
    //计算除去最大值、最小值后的平均数:
    [Serializable]
    [Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.Native)]
    public struct TrimmedMean
    {
        private int numValues;
        private SqlMoney totalValue;
        private SqlMoney minValue;
        private SqlMoney maxValue;
       
        public void Init()
        {
            this.numValues = 0;
            this.totalValue = 0;
            this.minValue = SqlMoney.MaxValue;
            this.maxValue = SqlMoney.MinValue;
        }
     
        public void Accumulate(SqlMoney Value)
        {
            if (!Value.IsNull)
            {
                this.numValues++;
                this.totalValue += Value;
                if (Value < this.minValue) this.minValue = Value;
                if (Value > this.maxValue) this.maxValue = Value;
            }
        }
     
        public void Merge(TrimmedMean Group)
        {
            if (Group.numValues > 0)
            {
                this.numValues += Group.numValues;
                this.totalValue += Group.totalValue;
                if (this.minValue < Group.minValue) this.minValue = Group.minValue;
                if (this.maxValue > Group.maxValue) this.maxValue = Group.maxValue;
            }
        }
     
        public SqlMoney Terminate()
        {
            if (this.numValues < 3)
            {
                return SqlMoney.Null;
            }
            else
            {
                this.numValues -= 2;
                this.totalValue -= this.minValue;
                this.totalValue -= this.maxValue;
                return (this.totalValue / this.numValues);
            }
        }
    }

    ●>  Using the TrimmedMean Aggregate
    --Example:
    Select AVG(TotalDue) AS AverageTotal,
           dbo.TrimmedMean(TotalDue) AS TrimmedAverageTotal
    FROM Sales.SalesOrderHeader
     
    ●>  Managing User-Defined Aggregates
    If an assembly has been loaded into the database using CREATE ASSEMBLY, aggregates can be created or dropped。
     
    --Example:
    Create Aggregate [dbo].[TrimmedMean] (@Value [money])
    Returns[money]
    External Name [TrimmedMean].[TrimmedMean]
    GO
     
    Drop Aggregate [dbo].[TrimmedMean]
     
    --To get information about user-defined aggregates:
    Select * From sys.objects Where type = 'AF'
     

    ◆[CLR User-Defined Triggers]
    CLR triggers behave the same way as T-SQL triggers, bringing the same power to the table: centralization and encapsulation of logic. However, CLR triggers can be written in a .NET language and possibly take advantage of resources not easily accessible from T-SQL, such as regular expressions for data validation. CLR triggers can be used to define both DML (e.g., UPDATE, INSERT, and DELETE) and DDL triggers (e.g., CREATE TABLE).
     
    It’s important to remember when working with triggers that speed is of the essence. A trigger fires in the context of the transaction that manipulated the data. Any locks required for that data manipulation are held for the duration of the trigger’s lifetime.

    This concern is doubly important when working with the CLR. Triggers are not the place to contact web services, send e-mails, work with the file system, or do other synchronous tasks. Developers who need this functionality should investigate using technologies such as SQL Service Broker and SQL Server Notification Services.
     
    ●>  TriggerContext
    This object contains properties to assist with determining why the trigger fired. The most important of these are the TriggerAction property, which maps to an enumerator by the same name that contains every possible action that can cause a trigger to fire, and the EventData property, which contains XML data useful in DDL triggers.
     
    //Example:
    if (SqlContext.TriggerContext.TriggerAction == TriggerAction.Update)
    {
        // do something
    }
     
    ●>  Programming CLR Triggers
    --Example Code in 第 233/705 页
     
    //这个样例,Deploy时出错:
    //Error 1 Cannot find the object "HumanResources.Department" because it does not exist or you do not have permissions. CLRTriggers
    //不知为什么,这人表存在且有权限呀,在SSMS中都可以查询这个表,郁闷-_-!!! 。
    public partial class Triggers
    {
        [Microsoft.SqlServer.Server.SqlTrigger(Name = "ValidateYear",
                                                Target = "HumanResources.Department",
                                                Event = "FOR INSERT")]
        public static void ValidateYear()
        {
            SqlConnection conn = new SqlConnection("context connection=true");
            string sql = "SELECT COUNT(*) FROM INSERTED " +
                         "WHERE YEAR(ModifiedDate) <> 2005";
            SqlCommand comm = new SqlCommand(sql, conn);
            conn.Open();
            int numBadRows = (int)comm.ExecuteScalar();
            if (numBadRows > 0)
            {
                SqlPipe pipe = SqlContext.Pipe;
                //Roll back and raise an error
                comm.CommandText = "RAISERROR('Modified Date must fall in 2005', 11, 1)";
                try
                {
                    pipe.ExecuteAndSend(comm);
                }
                catch
                {
                    //do nothing
                }
                System.Transactions.Transaction.Current.Rollback();
            }
            conn.Close();
        }
    }

    ●>  Managing User-Defined Triggers
    If an assembly has been loaded into the database using CREATE ASSEMBLY, triggers can be created or dropped.
     
    --Example:
    CREATE TRIGGER ValidateYear
    ON HumanResources.Department
    FOR INSERT
    AS
    EXTERNAL NAME UserDefinedTriggers.Triggers.ValidateYear
    Go
     
    DROP TRIGGER ValidateYear
     
    --The sys.triggers catalog view contains information about both T-SQL and CLR triggers.
    --To get information about CLR triggers, filter the type column for the value TA:
    SELECT * FROM sys.triggers
    WHERE type = 'TA'

    ◆[Managing Assemblies]
     
    select top 10 * from sys.assemblies
    select top 10 * from sys.assembly_files
    select top 10 * from sys.assembly_modules
    select top 10 * from sys.assembly_types
    select top 10 * from sys.assembly_references

    ◆[Summary]
    When used prudently, CLR routines make powerful additions to SQL Server’s toolset.
    It’s important to remember that some caveats exist and that careful testing is required. That said, SQL Server 2005’s CLR integration should prove incredibly useful for most software shops.
  • 相关阅读:
    线程的简单介绍
    队列Joinablequeue的使用,以及生产者消费者模型的认识
    使用子线程来完成链接循环和通信循环
    使用socketserver实现简单的下载和上传
    类的绑定方法学习
    类的组合-多态-封装等特性的简单学习
    爬虫之亚马逊爬取
    JavaScript 面试中常见算法问题详解
    JavaScript 的 this 指向问题深度解析
    深入理解 JavaScript 中的函数
  • 原文地址:https://www.cnblogs.com/cxd4321/p/667757.html
Copyright © 2011-2022 走看看