Answer the question
In order to leave comments, you need to log in
Is it dangerous to execute such code in C# + T-SQL? Or is there a different way to write it?
Есть 3 таблицы. Основная SOME_GROUP и две дочерние, что видно из столбцов GROUP_ID.
У всех трёх таблиц первичный ключ:CONSTRAINT PK_BLA_BLA PRIMARY KEY CLUSTERED (ID)
Так же у дочерних таблиц есть внешние ключи (GROUP_ID), которые указывают на ID в таблице SOME_GROUP.
Эти строки в запросе приведены для удобства и понимания, что как выполняется.
BEGIN TRANSACTION
SET TRANSACTION ISOLATION LEVEL READ COMMITTED -- REPEATABLE READ
SELECT TOP(@Quantity) ID FROM SOME_GROUP WITH(UPDLOCK) WHERE REPLICATED <> 1
BEGIN TRANSACTION
SET TRANSACTION ISOLATION LEVEL READ COMMITTED -- REPEATABLE READ
SET DEADLOCK_PRIORITY LOW;
DECLARE @Quantity INT = 5;
-- Первый запрос, вызываемый из C# кода в одной транзакции.
-- 1 ------------------------------------------------------------------
UPDATE SOME_GROUP SET REPLICATED = 2
OUTPUT
INSERTED.ID
,INSERTED.NAME
WHERE ID IN(SELECT TOP(@Quantity) ID FROM SOME_GROUP WITH(UPDLOCK) WHERE REPLICATED <> 1)
-- Второй запрос, вызываемый из C# кода в одной транзакции.
-- 2------------------------------------------------------------------
UPDATE SOME_CHILD_ONE SET REPLICATED = 2
OUTPUT
INSERTED.ID
,INSERTED.GROUP_ID
,INSERTED.UPDATED
WHERE GROUP_ID IN(SELECT TOP(@Quantity) ID FROM SOME_GROUP WITH(UPDLOCK) WHERE REPLICATED <> 1) AND REPLICATED <> 1
-- Третий запрос, вызываемый из C# кода в одной транзакции.
-- 3 ------------------------------------------------------------------
UPDATE SOME_CHILD_TWO SET REPLICATED = 2
OUTPUT
INSERTED.ID
,INSERTED.GROUP_ID
,INSERTED.NAME
,INSERTED.CREATED
WHERE GROUP_ID IN(SELECT TOP(@Quantity) ID FROM SOME_GROUP WITH(UPDLOCK) WHERE REPLICATED <> 1) AND REPLICATED <> 1
-- 3 ------------------------------------------------------------------
COMMIT TRANSACTION
Answer the question
In order to leave comments, you need to log in
Ваш код не будет работать всегда предсказуемым образом. Основная проблема в том, что SELECT TOP без ORDER BY не гарантирует ни в коем случае одни и те же данные. Да, в вашем случае они скорее всего приходят в порядке из сохранения в кластерном индексе. Но если изменится индекс или добавится новый, то ваш код может перестать работать как ожидается.
Другая проблема в том, что несмотря на то, что подзапросы в WHERE одинаковые, они могут возвращать разные данные из-за первого UPDATE. Если у вас было 10 записей с REPLICATED =-10 (минус!), то до первого обновления подзапрос выдаст записи с 1 по 5, а после него с 6 по 10.
Совет: сохраните обновляемые ID в отдельную временную таблицу и присоединяйте ее для обновления.
Либо настройте внешние ключи и каскадное обновление.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question