【问题标题】:SQL CLR trigger: name of the context DBSQL CLR 触发器:上下文数据库的名称
【发布时间】:2010-07-28 16:59:42
【问题描述】:

我想在我的 SQL CLR 触发器中打开/关闭触发器递归。根据http://www.devx.com/tips/Tip/30031,我得打电话了

EXEC sp_dboption '<name of db>', 'recursive triggers', 'true'/'false'

有没有办法知道当前的数据库名称是什么?创建触发器时,我要求用户选择一个,但我不想将它写在表格中。

问候,

【问题讨论】:

    标签: sql-server triggers sqlclr


    【解决方案1】:

    有一种非常简单的方法可以找到触发 SQLCLR 触发器的数据库的名称:只需连接到上下文连接并获取 Database 属性。你甚至不需要执行查询:-)。

    以下内容应适用于所有 SQLCLR 对象类型(存储过程、函数、用户定义的聚合、用户定义的类型和触发器):

    string _DatabaseName;
    
    using (SqlConnection _Connection = new SqlConnection("Context Connection = true;"))
    {
        _Connection.Open();
        _DatabaseName = _Connection.Database;
    }
    

    就是这样!我刚刚在 SQLCLR 触发器中尝试过,效果很好。


    要记住限制触发器触发其他触发器的另一件事是TRIGGER_NESTLEVEL 函数。这在 @@PROCID 的值可用且包含触发器的 [object_id] 的 T-SQL 触发器中效果更好。因此,在 T-SQL 触发器中,您可以单独限制每个触发器的递归,但仍允许触发器在其他表上触发其他触发器。

    在SQLCLR中它仍然可以使用,但是没有Trigger的名字你只能限制所有的Trigger。这意味着,您可以阻止任何触发器在任何表上触发任何其他触发器,包括在同一个表上,但是没有办法限制 only 同一个触发器的触发,同时允许在其他表上触发可能会被相关触发器修改。只需使用上下文连接并通过SqlCommand.ExecuteScalar() 运行SELECT TRIGGER_NESTLEVEL();

    【讨论】:

      【解决方案2】:

      当你创建触发器的时候你就知道数据库是什么了...

      CREATE TRIGGER etc
      ....
      GO
      DECLARE @db varchar(100)
      SET @db = DB_NAME()
      EXEC sp_dboption @db, 'recursive triggers', 'true'/'false'
      

      【讨论】:

      • 是的,我知道,但触发器是 CLR 程序集。要在内部传递数据库名称,我必须将其写入表中,然后在触发器中读取。无论如何,据我了解,我可以使用 DB_NAME() 而不是 '',对吗?还是我应该声明变量?
      • 你必须声明一个变量。它也可能无法在触发器内工作。
      【解决方案3】:

      我找到了更好的解决方案。

      我必须完全避免调用 EXEC sp_dboption。相反,我必须创建一个临时表作为“无递归”标志,然后在触发器开始时检查该表是否存在,如果该表存在则退出。

      为什么是临时表?

      1. 它在会话结束时被杀死。无需重置标志(在特殊情况下),否则这是必要的,以避免触发器永久关闭。
      2. AFAIK,它正在为每个连接独立创建和终止。因此,如果用户同时更改数据,则不会发生冲突(这对于 EXEC sp_dboption 是不可避免的)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多