Здравствуйте, Poul_Ko, Вы писали:
P_K>Раз мы прочитали заказы и собираемся их обновлять, то по-хорошему их также нужно блокировать. Чтобы никто другой не мог параллельно изменить / удалить заказ.
В приведённой архитектуре при любом изменении заказа нужно получать блокировки на продукт — ровно по той же причине.
-- внесение изменения в заказ
begin tran -- read_committed
select @old_productId = productId from orders with updlock where id = @order_id -- заранее захватываем U-блокировку, чтобы избежать дедлоков
set @product1 = min(@old_productId, @new_productId) -- предотвращаем дедлоки, вводя строгую упорядоченность в захвате локов на продукт
set @product2 = max(@old_productId, @new_productId)
sp_getapplock('product_'+@product1)
sp_getapplock('product_'+@product2)
update orders set productId = @new_productId, cost = @new_Cost, ..., where id = @order_id
commit tran
-- удаление заказа
begin tran -- read_committed
select @productId = productId from orders with updlock where id = @order_id -- заранее захватываем U-блокировку, чтобы избежать дедлоков
sp_getapplock('product_'+@productIв)
delete from orders set productId = @new_productId, cost = @new_Cost, ... where id = @order_id
commit tran
P_K>Речь не об этом. При определённой сложности (в плане количества ветвлений) простая реализация логики в виде одного метода становится невозможной. Получаем ад из ветвлений и всяких флагов... В итоге всё это рефакторится в отдельные классы (например, что-то вроде стратегий), приобретает понятную форму и тестируемость. На хранимых процедурах такой финт невозможен, думаю согласитесь.
Поэтому я вам и говорю про Linq. Он позволяет писать аккуратный и понятный код, который будет транслироваться в корректный SQL без лишних усилий с вашей стороны.