Доступ к имени триггерной / родительской таблицы внутри триггера SQLCLR - PullRequest
2 голосов
/ 04 февраля 2020

Я создаю относительно простую SQL CLR в C#.

Работа этого CLR заключается в публикации sh событий в Azure Event Grid Topi c.

Я хотел бы иметь возможность вызывать этот конкретный CLR из любого количества триггеров для любого количества таблиц (на самом деле их будет мало).

Учитывая приведенный ниже основной код, как можно точно получить имя таблицы, которая вызвала / сработала триггер? Я мало знаю, с чего начать.

Я хотел бы иметь возможность удалить атрибут SqlTrigger и каким-то образом получить доступ к имени таблицы для свойства var table.

// I Would like to leave the attribute commented out
//
//[Microsoft.SqlServer.Server.SqlTrigger(Name = "PublishToEventGridTrigger",
//     Target = "NamesOfThings", Event = "FOR UPDATE, INSERT, DELETE")]
public static void PublishToEventGridTrigger()
{
    // TODO - How should these settings be handled?     
    //        Not sure if config files are accessible... To test..
    // ***************************************************************

    string topicHost = "https://####.eventgrid.azure.net/api/events";
    string topicKey = "####";

    // TODO - Get Table name for this
    var table = "How Do I set This";
    string eventType = $"##.{table}.{SqlContext.TriggerContext.TriggerAction.ToString()}";

    // ***************************************************************

    try
    {
        // extract data involved in trigger
        // Create the Event object
        EventGridEvent evt = new EventGridEvent("QWDBEvent", eventType, new
                      TriggerData(SqlContext.TriggerContext, SqlContext.Pipe));

        // Publish the event
        Event.Publish(topicHost, topicKey, evt);
    }
    catch (Exception ex)
    {
        //TODO - how do we handle these through SQL CLR? 
        // Going with a fire-and-forget for now    
        SqlContext.Pipe.Send($"Failure firing {ex.Message}");        
    }
    SqlContext.Pipe.Send($"Trigger fired");
}

1 Ответ

1 голос
/ 04 февраля 2020

Это изначально не поддерживается и не очень легко сделать sh. На самом деле у меня есть макет, который делает это, но у меня не было времени опубликовать sh. Конечно, не прямо. На данный момент вы можете взглянуть на оба ответа на этот вопрос:

SQL CLR Trigger - получить исходную таблицу

И я обновлю этот ответ, когда Я очистил и опубликовал свое решение.

HOWEVER , в то время как вы говорите, что будет применено только несколько таблиц, имейте в виду, что триггеры выполняются в контекст транзакции, частью которой является оператор DML (или даже DDL). Это имеет два последствия:

  1. чем дольше длится триггер, тем дольше длится операция DML / DDL, следовательно, дольше удерживаются блокировки на объекте (объектах). Это может оказать неблагоприятное влияние на параллелизм / производительность. Это заставляет многих нервничать из-за того, что операторы DML / DDL ie обращаются к вызовам веб-служб для локальных (intr anet / той же сети) служб, но через inte rnet вводит опасный, сильно изменяющийся риск в процесс это должно быть довольно просто. Конечно, если вы используете Azure VM или Azure SQL Managed Instance, то, возможно, задержка достаточно мала, чтобы этого было «достаточно» безопасно. В любом случае, будьте очень осторожными! (Для ясности: этот риск не снижается при использовании триггера T- SQL для выполнения хранимой процедуры SQLCLR; это все та же транзакция )
  2. , если триггер не работает / выдает ошибку, по умолчанию которая прервет транзакцию и откатит операцию DML (или DDL). Это намеренное поведение? Обычно отказ регистрировать событие не должен прерывать саму операцию, верно? Поэтому вам, вероятно, потребуется проглотить ошибку (или, по крайней мере, записать ее в текстовый файл, возможно).

Вы должны быть в состоянии отделить операцию DML / DLL от части регистрации, настроив Service Broker для обработки вызова службы регистрации. В этом случае вы должны:

  1. Использовать триггер T- SQL
    1. , чтобы получить имя таблицы с помощью:
      SELECT tab.[name]
      FROM   sys.objects tab
      WHERE  tab.[object_id] = (
                        SELECT trg.[parent_object_id]
                        FROM sys.objects trg
                        WHERE  trg.[object_id] = @@PROCID
                               );
      
    2. Соберите любую другую информацию для регистрации возможно из таблиц INSERTED и / или DELETED (после этого у вас не будет доступа к ним; хотя вы можете перепаковать данные в этих двух таблицах как XML, чтобы отправить их как часть сообщения Service Broker - например, SELECT * FROM inserted FOR XML RAW('ins');)
    3. Поставить в очередь сообщение для Service Broker, включая собранную информацию
  2. Использование Service Broker
    1. будет обрабатывать сообщения асинхронно из DML Операции / DLL
    2. могут выполнять хранимую процедуру SQLCLR, передавая информацию, собранную в триггере T- SQL, для вызова службы регистрации (внутренней или внешней сети)

Имейте в виду (поскольку вы упоминали получение значения PK, на которое влияют, из таблиц INSERTED и DELETED), что в этих таблицах может быть несколько строк, если операция DML затрагивала несколько строк (т. Е. никогда предполагает одна строка для работы с DML ations).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...