Как полностью заблокировать строку в Entity Framework

Я работаю с ситуацией, когда мы имеем дело с денежными операциями.

Например, у меня есть таблица кошельков пользователей с их балансом в этом ряду.

UserId; Wallet Id; Balance

Теперь на нашем веб-сайте и в веб-сервисах каждый раз, когда происходит определенная транзакция, нам необходимо:

  1. проверьте, достаточно ли средств для выполнения этой транзакции:
  2. вычесть расходы по сделке из баланса.

Как и как правильно блокировать эту строку / сущность на все время моей транзакции?

Из того, что я прочитал, есть некоторые решения, в которых 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: предотвращение грязного чтения в хранимой процедуре

Другие вопросы по тегам