Запускать триггер для каждой вставленной строки с помощью SqlBulkCopy

Я использую класс SqlBulkCopy для вставки 50 тыс. Строк в таблицу. tbl_records Я установил триггер After Insert для этой таблицы и использую следующий код

SqlBulkCopy SqlBc1 = new SqlBulkCopy(strConnString, SqlBulkCopyOptions.FireTriggers);

// Set DataReader For SqlBulkCopy

sqlComm = new SqlCommand(strQuery, sqlTemCon);
sqlComm.CommandTimeout = 3600000;
sqlComm.CommandType = System.Data.CommandType.Text;
SqlDataReader dReader = sqlComm.ExecuteReader();       
SqlBc1.WriteToServer(dReader);

Но после выполнения прог. Он запускает триггер только для First строк из вставленных 50 КБ.

Я хочу, чтобы он запускался для каждой строки. Как я могу это сделать??


person Rajeev Kumar    schedule 25.09.2013    source источник
comment
Я уже проверил этот ответ, но в моем случае после добавления SqlBulkCopyOptions он все еще запускает триггер только для первой строки, вставленной из 50 тыс. Строк   -  person Rajeev Kumar    schedule 25.09.2013
comment
stackoverflow.com/questions/5805413/   -  person Karthik    schedule 25.09.2013


Ответы (4)


Триггеры никогда не срабатывают для каждой строки. Они запускаются для всех строк соответствующего оператора DML. Перепишите свой триггер, чтобы он мог работать с таблицей INSERTED, содержащей много строк. В любом случае это лучшая практика и обязательная практика.

это запускающий триггер только для первой строки, вставленной из 50 тыс. строк

Вы, должно быть, неправильно интерпретируете ситуацию, возможно, потому, что не знали, что триггеры могут содержать несколько строк в виртуальных таблицах.

person usr    schedule 25.09.2013

Размер пакета объекта SqlBulkCopy по умолчанию - это полный набор строк.

Вот что MSDN говорит о значениях свойства BatchSize: «Ноль (значение по умолчанию) указывает, что каждая операция WriteToServer является одним пакетом».

В этом случае триггер сработает один раз, но в таблице вставленных будут записи для всех затронутых записей.

person Kevin Buchan    schedule 25.09.2013

Если другой человек столкнется с этой проблемой и ищет решение, я также опубликую здесь свои выводы.

ВАЖНО: usr уже дал ответ, но я немного его объясню.

Во-первых, это то, что Microsoft документация говорит о массовой вставке,

Если FIRE_TRIGGERS не указан, триггеры вставки не выполняются.

FIRE_TRIGGERS Указывает, что любые триггеры вставки, определенные в целевой таблице, выполняются во время операции массового импорта. Если триггеры определены для операций INSERT в целевой таблице, они запускаются для каждого завершенного пакета.

FIRE_TRIGGERS - это аргумент, используемый с BULK INSERT оператором T-SQL.

И если вы пытаетесь использовать массовую вставку с SqlBulkCopyclass (.Net Framework / Core), вам необходимо использовать SqlBulkCopyOptions Enum (документы).

Вы можете использовать перечисление SqlBulkCopyOptions при создании экземпляра SqlBulkCopy, чтобы изменить поведение методов WriteToServer для этого экземпляра.

Вот образец,

var options = SqlBulkCopyOptions.CheckConstraints | SqlBulkCopyOptions.FireTriggers | SqlBulkCopyOptions.KeepIdentity;
var bulkCopy = new SqlBulkCopy(connectionString, options);

OK. Теперь триггеры будут работать с массовой вставкой, но почему только для одной записи. Прочтите еще раз, что Microsoft сказала о FIRE_TRIGGER аргументе.

Если триггеры определены для операций INSERT в целевой таблице, они запускаются для каждого завершенного пакета.

Это означает, что ваш триггер будет работать сразу для всей партии. Но ваш пакет содержит более одной строки. Следовательно, ваш алгоритм триггера (то, что вы должны сделать с одной записью) будет работать для одной записи, а не для всех записей.

Теперь вы знаете, почему это не работает для всех, поэтому решение состоит в том, чтобы улучшить ваш триггер для работы с несколькими строками. Это означает, что итерация бросает все строки с INSERTED временной таблицей и выполняет ваш алгоритм для всех записей. Вы можете использовать CURSOR или простой WHILE LOOP. Тебе решать.

Вы можете найти примеры здесь.

person Emalsha Rasad    schedule 19.02.2020

Я попробовал это, и это сработает.

Надеюсь, это вам поможет ..

CREATE TRIGGER Triggername ON TableName After INSERT AS SET NOCOUNT ON;

insert into TargetTable (Fields) SELECT (i.field1,i.field2,i.field3,....,i.fieldn) FROM inserted i GO

person Pravin Tukadiya    schedule 23.02.2016