«Конвертировать» необработанный SQL в чистый Entity Framework - PullRequest
0 голосов
/ 14 октября 2018

Я пытаюсь выполнить операцию с базой данных через C # и Entity Framework, где я обновляю счетчик на основе столбцов в таблице и возвращаю вставленное значение.

Мне нужно, чтобы это было в одной строке, чтобысохранить безопасность потоков.

Необработанный SQL, который я создал, работает, но я действительно не хочу оставлять необработанный SQL вместо «чистого» кода EF.Буду признателен за помощь в переводе этого.

int counter = db.Database.SqlQuery<int>($"update [dbo].[table1] set [Counter] = (case when [Counter] < [Maximum] then [Counter] + 1  else [Minimum] end) output inserted.Counter Where Id = {myId}").First();

Ответы [ 2 ]

0 голосов
/ 14 октября 2018

Создайте хранимую процедуру, затем вызовите процедуру из db_entity с аргументами

0 голосов
/ 14 октября 2018

EF LINQ запросы только SELECT.Единственное, что вы можете сделать без любого SQL, - это запускать запросы, сохранять изменения в сущностях и выполнять транзакции.И нет никакого способа сделать то, что вы хотите (по крайней мере, в SQL Server) без предложения OUTPUT или подсказок блокировки.

Это распространенное заблуждение, что транзакция, использующая уровень изоляции SERIALIZABLE , будет работать здесь,Но это не так.Когда вы читаете в транзакции SERIALIZABLE, вы помещаете общие (S) блокировки в строки (и диапазоны), удовлетворяющие предикатам запроса, и удерживаете эти блокировки в течение всей транзакции.Поскольку это общие блокировки, две SERIALIZABLE транзакции могут читать одну и ту же строку.Затем, если любая из транзакций попытается преобразовать общую блокировку в эксклюзивную блокировку для обновления строки, она будет заблокирована другой транзакцией.Если оба пытаются обновить, возникает тупик.

Таким образом, вы могли бы поместить код в цикл, перехватывая и повторяя попытки при взаимных блокировках, но это не очень рекомендуется в высокочастотной транзакции, и тупик обрекает всю вашу транзакцию, поэтомуцикл может потребоваться повторить много других операторов.Значительно хуже, чем шаблон UPDATE… OUTPUT, используемый здесь.

Конечно, шаблон намного лучше - вместо этого использовать несколько объектов SEQUENCE .Потому что даже с UPDATE ... OUTPUT только одна транзакция может генерировать значение за раз, а другие сеансы будут ждать, пока эта транзакция не завершится, пока они не смогут сгенерировать значение.С помощью ПОСЛЕДОВАТЕЛЬНОСТИ генерация не транзакционная, и несколько сеансов могут генерировать значения, не блокируя транзакции друг друга.

Здесь лучшее, что вы можете сделать, - это обернуть эту логику в хранимую процедуру и затем вызвать ее из функциина вашем DbContext.

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