Как полностью заблокировать строку в Entity Framework
Я работаю с ситуацией, когда мы имеем дело с денежными операциями.
Например, у меня есть таблица кошельков пользователей с их балансом в этом ряду.
UserId; Wallet Id; Balance
Теперь на нашем веб-сайте и в веб-сервисах каждый раз, когда происходит определенная транзакция, нам необходимо:
- проверьте, достаточно ли средств для выполнения этой транзакции:
- вычесть расходы по сделке из баланса.
Как и как правильно блокировать эту строку / сущность на все время моей транзакции?
Из того, что я прочитал, есть некоторые решения, в которых EF отмечает объект, а затем сравнивает этот знак, когда сохраняет его обратно в БД, однако что он делает, когда другой пользователь / программа уже отредактировал сумму?
Могу ли я достичь этого с EF? Если нет, какие еще варианты у меня есть?
Может ли вызов хранимой процедуры позволить мне правильно заблокировать строку, чтобы никто другой не мог получить доступ к этой строке в SQL Server, в то время как программа A имеет блокировку?
3 ответа
EF не имеет встроенного механизма блокировки, вам, вероятно, придется использовать необработанный запрос, например
using (var scope = new TransactionScope(...))
{
using (var context = new YourContext(...))
{
var wallet =
context.ExecuteStoreQuery<UserWallet>("SELECT UserId, WalletId, Balance FROM UserWallets WITH (UPDLOCK) WHERE ...");
// your logic
scope.Complete();
}
}
Вы можете установить уровень изоляции для транзакции в платформе Entity, чтобы никто другой не мог ее изменить:
YourDataContext.Database.BeginTransaction(IsolationLevel.RepeatableRead)
Сводка RepeatableRead: Блокировки устанавливаются на все данные, которые используются в запросе, не позволяя другим пользователям обновлять данные. Предотвращает неповторяющиеся чтения, но фантомные строки все еще возможны.
Весь смысл транзакционной базы данных заключается в том, что потребитель данных определяет, насколько изолированным должен быть их взгляд на данные.
Независимо от того, сериализована ли ваша транзакция, кто-то другой может выполнить грязное чтение тех же данных, которые вы только что изменили, но не зафиксировали.
Прежде всего, вам следует позаботиться о целостности своего представления, а затем принять только ухудшение качества этого представления, чтобы повысить производительность системы там, где вы уверены, что это требуется.
Оберните все в TransactionScope
с Serialized
уровень изоляции, и вы лично не можете пойти не так. Сбрасывайте уровень изоляции только тогда, когда вы видите, что это действительно необходимо (то есть, когда что-то не так, иногда это нормально).
Кто-то спрашивает об этом здесь: SQL Server: предотвращение грязного чтения в хранимой процедуре