SQL CLR Trigger - get Target / Table name

拥有回忆 提交于 2019-12-12 20:47:02

问题


Track column changes - single SQL CLR Trigger for multiple Targets/Tables


SQL CLR Trigger:

Is there a way to get Target / Table name from CLR code?

Purpose:

I'm building a universal SQL CLR Trigger to track column changes in multiple Tables.

Info:

The same CLR trigger can be bound to multiple Tables.

As long as CLR Trigger is bound to a Table, it fires just fine on any Table no matter what Target/Table was specified in CLR Trigger Attribute. It means I can create 1 CLR Trigger and use it for all Tables that require change tracking.

The problem is in calling table name / trigger name identification within the Trigger. I tried all DMV objects, so far nothing that solves the problem. Btw, @@PROCID is not accessible in CLR.

PS: I have a solution, but is can not be considered as nice and reliable.


回答1:


The tip is to have the Trigger Target set to the right level. Although it's not CLR specific the details can be found in MSDN here but the following would probably work for you.

[Microsoft.SqlServer.Server.SqlTrigger (Name="TriggerName", Target="database", Event="FOR UPDATE")]

Then to figure out what table or field changed access the EventData which is in a SqlXml variable. I created a class similar to the following to access the properties in a structured way.

using System.Data.SqlTypes;
using System.Xml;
using System.Xml.Serialization;

namespace CLRSQLTrigger
{

public class SqlEventData
{
    readonly XmlDocument document = new XmlDocument();

    public SqlEventData(SqlXml sqlXml)
    {
        if (sqlXml != SqlXml.Null)
        {
            document.LoadXml(sqlXml.Value);
        }
    }
    public string EventType
    {
        get { return document.GetElementsByTagName("EventType")[0].InnerText; }
    }
}

}

The values received by a given action are alot easier to decode by dumping the SqlXml variable that is returned when your event is fired. Once you have those values you can use a syntax similar to the EventType Property above or use the GetElementsByTagName method in your code directly. There are literally 100+ events and each event has 4-12 fields, so that part is up to you. If you are serious there is an XSD of the different combinations but it might slow you down compared to the debug method. The XSD path is going to be something like

C:\Program Files\Microsoft SQL Server\100\Tools\Binn\schemas\sqlserver\2006\11\events




回答2:


public partial class Triggers
    {
        [SqlTrigger(Name = "TriggerName", Target = "TableName", Event = "FOR UPDATE")]
        public static void TriggerName ()
        {
            SqlTriggerContext triggerContext = SqlContext.TriggerContext;

            if (triggerContext.TriggerAction == TriggerAction.Update)
            {

                SqlConnection connection = new SqlConnection("Context Connection=true");
                SqlCommand command = new SqlCommand();
                command.Connection = connection;
                command.CommandText = "SELECT * FROM INSERTED,DELETED";
                connection.Open();
                SqlDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);
                if (SqlContext.TriggerContext.IsUpdatedColumn(reader.GetOrdinal("State")))
                {
                    reader.Read();
                    long MessageID = Convert.ToInt64(reader["MessageID"]);
                    int State = Convert.ToInt32(reader["State"]);
                    reader.Close();

                    if (State == 1)
                        FunctionName.SendMassage(MessageID); 
                }
            }
        }
    }


来源:https://stackoverflow.com/questions/7564383/sql-clr-trigger-get-target-table-name

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!