SQL CLR 触发器 - 获取目标/表名称

发布于 2024-12-06 13:00:55 字数 476 浏览 2 评论 0原文

跟踪列更改 - 多个目标/表的单个 SQL CLR 触发器


SQL CLR 触发器:

有没有办法从 CLR 代码获取目标/表名称?

目的:

我正在构建一个通用 SQL CLR 触发器来跟踪多个表中的列更改。

信息

同一个 CLR 触发器可以绑定到多个表。

只要 CLR 触发器绑定到表,无论 CLR 触发器属性中指定什么目标/表,它都会在任何表上正常触发。这意味着我可以创建 1 个 CLR 触发器并将其用于所有需要更改跟踪的表。

问题出在触发器内调用表名/触发器名标识。 我尝试了所有 DMV 对象,到目前为止还没有解决问题。顺便说一句,@@PROCID 在 CLR 中不可访问。

PS:我有一个解决方案,但不能被认为是好的和可靠的。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

转身以后 2024-12-13 13:00:55

提示是将触发目标设置为正确的级别。虽然它不是特定于 CLR 的,但可以在 MSDN 此处 中找到详细信息,但是以下可能对你有用。

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

然后,要找出更改的表或字段,请访问 SqlXml 变量中的 EventData。我创建了一个类似于以下内容的类,以结构化方式访问属性。

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; }
    }
}

通过转储事件触发时返回的 SqlXml 变量,给定操作接收到的值更容易解码 获得这些值后,您可以使用与上面的 EventType 属性类似的语法,或者直接在代码中使用 GetElementsByTagName 方法。实际上有 100 多个事件,每个事件有 4-12 个字段,因此这部分由您决定。如果您是认真的,那么可以使用不同组合的 XSD,但与调试方法相比,它可能会减慢您的速度。 XSD 路径将类似于

C:\Program Files\Microsoft SQL
服务器\100\Tools\Binn\schemas\sqlserver\2006\11\events

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

稍尽春風 2024-12-13 13:00:55
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); 
                }
            }
        }
    }
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); 
                }
            }
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文