我有一个数据库,其中数据必须有条件地复制到同一服务器上的不同数量的数据库。接收表将具有相同的名称,但只有关键列。
我想将数据库浏览逻辑放在SQLCLR中,并在源表中更新数据后立即做出反应。因此,我希望重复使用相同的复制方法,根据当前更新的表复制键值。
internal static void ReplicateToInstances()
{
if (!IsTableWriteTriggerContextAvailable()) throw new InvalidOperationException();
string currentlyUpdatedTable; // = SqlContext.TriggerContext.??????
// rest of the code, irrelevant to the current issue.
}
有没有办法知道当前TriggerContext
实例在哪个表上?
答案 0 :(得分:1)
应该显而易见,但不幸的是,它不是。 T-SQL触发器可以使用@@PROCID
,然后在sys.objects
中查找父对象,但对于SQLCLR则不然。这是一个Microsoft Connection项目,建议修复此问题:
A SQLCLR trigger should be given the parent object in the SQLTriggerContext
这里有一个关于重复问题的解决方法:
Retrieve the sqlobject that fired the trigger in clr
该解决方法的问题(即使用CONTEXT_INFO
)是,如果满足以下任一条件,它就不起作用:
CONTEXT_INFO已用于其他目的。
触发器可以更新一个表格,该表格上还有一个需要知道其父对象名称的SQLCLR触发器。
但是,使用sp_settriggerorder
程序将订单设置为First
是正确的。
我确实已经解决了可能工作的问题,即使在嵌套的触发器方案中也是如此,但我还没有时间对其进行测试(请参阅 UPDATE 以下部分)。但是,这个概念是在INSERT, UPDATE, DELETE
触发器中执行以下操作(以及将触发器顺序设置为First
):
CREATE TRIGGER [SchemaName].[tr_SetTriggerInfo]
ON [SchemaName].[TableName]
AFTER INSERT, DELETE, UPDATE
AS
BEGIN
CREATE TABLE #TriggerInfo (TriggerObjectID INT, TriggerName sysname,
ParentObjectID INT, ParentName sysname, TriggerNestLevel INT);
INSERT INTO #TriggerInfo (TriggerObjectID, TriggerName,
ParentObjectID, ParentName, TriggerNestLevel)
SELECT @@PROCID,
trggr.[name] AS [TriggerName],
trggr.[parent_object_id] AS [ParentObjectID],
OBJECT_NAME(trggr.[parent_object_id]) AS [ParentName],
TRIGGER_NESTLEVEL(@@PROCID, 'AFTER', 'DML') AS [TriggerNestLevel]
FROM sys.objects trggr
WHERE trggr.[object_id] = @@PROCID;
END;
GO
EXEC sp_SetTriggerOrder @TriggerName = N'[SchemaName].[tr_SetTriggerInfo]',
@Order = N'First',
@StmtType = N'DELETE';
EXEC sp_SetTriggerOrder @TriggerName = N'[SchemaName].[tr_SetTriggerInfo]',
@Order = N'First',
@StmtType = N'INSERT';
EXEC sp_SetTriggerOrder @TriggerName = N'[SchemaName].[tr_SetTriggerInfo]',
@Order = N'First',
@StmtType = N'UPDATE';
GO
此应该的工作原因如下:
使用"Context Connection = true;"
的ConnectString的SQLCLR触发器可以从本地临时表中读取。
本地临时表在嵌套方案中的行为如下:
CREATE TABLE
语句,而不是出错,则会创建该表的 new 副本现在,父上下文中的同名临时表将不可访问(即隐藏)。这意味着,如果您处于第3级,那么当该级别完成时,在级别2中运行的触发器的代码仍将具有级别2值,而不是级别3值。 CONTEXT_INFO
这是不可能的,这就是CONTEXT_INFO
不适用于嵌套场景的原因:级别3将覆盖级别2的值,所以当控件返回到级别2时,它现在有CONTEXT_INFO
中的错误值。鉴于我们只能将单个Trigger设置为" First"而不是控制哪一个是"第二" (除非你从来没有超过3个触发器,在这种情况下你也可以使用" Last"位置),那么你不能保证SQLCLR触发器会在" First&#之后立即触发34;触发器,如果另一个触发器触发修改其上具有此触发器设置的表,那么CONTEXT_INFO
中的数据已损坏。
<强>更新强>
实际上,上面的临时表解决方案可能不会起作用,因为一旦T-SQL触发器结束(即SQLCLR触发器触发之前),本地临时表可能会消失。我还需要在下周测试一下。如果这是实际行为并且本地临时工作不起作用,那么我有另一个想法应该有效。