如何将参数传递给外部(SQLCLR)SQL Server触发器

时间:2017-01-03 09:53:31

标签: .net sql-server tsql sqlclr database-trigger

我创建了一个调用这样的程序集的Trigger:

         UIGraphicsBeginImageContext(drawImage.frame.size)
            var context = UIGraphicsGetCurrentContext()

            drawImage.image.draw(in: CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height - 50))

            context?.move(to: fromPoint)
            context?.addLine(to: toPoint)
            context?.setLineCap(.butt)
            context?.setLineWidth(2)
            context?.setBlendMode(.clear)
            context?.setShouldAntialias(true)

            UIColor.clear.set()

            context?.strokePath()

            let newImage = UIGraphicsGetImageFromCurrentImageContext()!

该程序集中的.NET代码执行如下操作:

CREATE TRIGGER Testrigger ON STATION  
FOR INSERT 
AS EXTERNAL NAME assemblytest.[WriteTimeInfile.Program].Testrigger 

我希望能够将创建的行或更新的行作为参数传递,如下所示:

namespace WriteTimeInfile
{
    public class Program
    {
        [SqlTrigger(Name = @"Testrigger", Target = "[dbo].[STATION]", Event = "FOR INSERT, UPDATE, DELETE")]
        public static void Testrigger()
        {
            File.AppendAllText(@"C:\Users\Vivien\date.txt",
            DateTime.Now.ToString() + Environment.NewLine);
        }
    }
}

我在StackOverflow上发现了一个7岁的topic,它告诉我无法将参数传递给CLR程序集。
我在问最近的SQL Server版本是否可以。

你知道是否有办法,如果有,请怎么做?

2 个答案:

答案 0 :(得分:3)

不,您不能直接将参数传递给SQLCLR触发器。但是,您可以通过几种方式间接传递值(与常规T-SQL触发器相同):

  1. 本地临时表
  2. SET CONTEXT_INFO / CONTEXT_INFO
  3. 在SQL Server 2016或更高版本上:sp_set_session_context / SESSION_CONTEXT
  4. 在所有情况下,您都可以通过执行带有输出SqlCommand的{​​{1}}来获取值,以将值拉入.NET代码中。 (请参阅最后关于使用的说明)。

    但是,如果您只想要SqlParameter和/或inserted表的值,那么它们就不是参数或参数。仅deleted使用SELECT使用SqlCommand作为连接字符串的人Context Connection = trueSqlDataReader。您可以在CLR Triggers部分的Sample CLR Trigger的MSDN页面中查看此示例。

    关于将值传递给不属于DML操作的触发器的注意事项:

    虽然它不是非常共同的,但确实有一些用例可以将一条信息从主要上下文传递到事件链中的一个或多个触发器。我遇到的两个最常见的情况是:1)将基于应用程序的登录或UserID(不是SQL Server的一部分)传递给审核触发器,以删除行(因为该信息无法添加到{的ModifiedBy列中{1}}操作),以及2)根据条件暂时禁用触发器。是的,这是可能的,它确实有效。请在DBA.StackExchange上查看我的以下答案:

答案 1 :(得分:1)

INSERTED和DELETED伪表始终可用于在SQLCLR触发器内直接查询,如文档的this 9+ years old version所示。你总是可以查询它们,例如:

using (SqlConnection conn = new SqlConnection("context connection=true"))
{
    conn.Open();
    SqlCommand sqlComm = new SqlCommand();
    SqlPipe sqlP = SqlContext.Pipe;

    sqlComm.Connection = conn;
    sqlComm.CommandText = "SELECT UserName from INSERTED";

    userName.Value = sqlComm.ExecuteScalar().ToString();

    if (IsEMailAddress(userName.Value.ToString()))
    {
        sqlComm.Parameters.Add(userName);
        sqlComm.CommandText = "INSERT UsersAudit(UserName) VALUES(@username)";
        sqlP.Send(sqlComm.CommandText);
        sqlP.ExecuteAndSend(sqlComm);
    }
}

最新的样本是相同的。

您不需要将它们作为参数传递,就像您不需要将它们作为参数传递给普通触发器一样。这些表始终可用于查询。

我怀疑这些表没有作为例如上下文对象的集合公开,因为这需要从SQL Server的缓冲区中复制它们(浪费CPU和内存)。另一个原因是无法有效地查询集合。您要么必须使用LINQ(使用更多的CPU),要么只是遍历整个内容(内存和CPU浪费)。内存浪费将是一个更大的问题,因为这个内存可以用来缓冲更多的数据和索引,从而加快访问速度。

我怀疑你链接的问题想要问同样的事情,但OP认为伪表必须作为参数传递。所以他询问了参数而不是实际问题。