У меня есть две таблицы.
Обороты кошелька и баланс кошелька.
Оборот кошелька - это кредитные и дебетовые операции через кошелек в определенной валюте и для конкретного клиента.
Баланс кошелька содержит для каждого клиента и валюты не более одной записи, которая содержит баланс для клиента и валюты. Баланс является результатом суммы кредитов и дебетов от оборотов кошелька.
Я хочу, чтобы приложение работало так, что, когда я добавляю оборот в таблицу оборотов, мне нужно пересчитать таблицу баланса путем добавления суммы текущего оборота. Если запись о валюте и клиенте текущего оборота еще не существует, я хотел бы создать новую.
Проблема заключается в том, как запретить приложению создавать несколько записей сальдо для одного и того же клиента и валюты в таблице сальдо.
Представьте себе, что я добавляю оборот для клиента с id = 1 и валютой = USD.
Запись еще не существует, поэтому ее следует создать.
Но что происходит, когда два одновременно работающих пользователя приложения A и B одновременно добавляют оборот для клиента 1 и валюты USD?
Что мне следует сделать, чтобы добиться поведения, чтобы при создании учетной записи баланса кошелька пользователем A в первый раз, когда она не была сохранена в базе данных, второму пользователю приложения B придется подождать, пока первый пользователь подтвердит свои записи Только для чтения текущего баланса (который содержит обновленный баланс от пользователя A) и продолжения с правильным значением баланса?
Может ли что-то подобное быть достигнуто? Как я должен сообщить nhibernate, что запись баланса с идентификатором клиента = 1 и валютой = USD уже создала некоторый пользователь, и поэтому, когда другой пользователь ищет эту комбинацию в таблице, эта запись уже создана, и пользователь должен дождаться, пока пользователь A совершает это?
Код GetOrCreateBalance:
public ClientWalletBalance GetOrCreateWalletBalance(int clientId, int currency)
{
var clientObj = ClientService.GetClient(clientId);
var res = clientObj.WalletBalances.FirstOrDefault(x => x.Currency.Id == currency);
if (res == null)
{
res = new ClientWalletBalance()
{
Client = clientObj,
Currency = ClientService.GetCurrency(currency),
};
};
clientObj.WalletBalances.Add(res);
return res;
}
Я уже знаю, что это может быть достигнуто
session.Lock (объект, LockMode.Upgrade);
Я просто не совсем понимаю, если я заблокирую только что созданный объект, который еще не сохранен в БД - так что с ним не связан идентификатор, как nhibernate узнает, что комбинация клиента 1 и валюты USD уже была создана, это некоторые другие пользователи "память?"
Каков стандартный рецепт для подобных случаев, пожалуйста?
Большое спасибо,
Peter
РЕДАКТИРОВАТЬ 1:
До сих пор я заканчивал с чем-то вроде этого:
Телефонный код:
using (ISession session = NHibernateConfiguration.ReturnOpenedSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
var cwb = Service.OrderAndPaymentService.GetOrCreateWalletBalance(clientId, currency, delay);
response.Error = cwb.Balance.ToString();
transaction.Commit();
}
}
`
Код звонка: `
public ClientWalletBalance GetOrCreateWalletBalance(int clientId, int currency, int delay = 0)
{
var clientObj = ClientService.GetClient(clientId);
var res = clientObj.WalletBalances.FirstOrDefault(x => x.Currency.Id == currency);
if (res != null)
{
NHibernateConfiguration.GetCurrentSession().Lock(res, LockMode.Upgrade);
}
else
{
res = new ClientWalletBalance()
{
Client = clientObj,
Currency = ClientService.GetCurrency(currency),
Balance = delay,
};
clientObj.WalletBalances.Add(SaveClientWalletBalance(res));
NHibernateConfiguration.GetCurrentSession().Lock(res, LockMode.Upgrade);
}
System.Threading.Thread.Sleep(delay * 1000);
return res;
}
`
Но все еще существует проблема с возможностью того, что два разных веб-пользователя будут вызывать одну и ту же комбинацию идентификатора клиента и валюты в первый раз, в этом случае будут созданы две записи для одного клиента и валюты. И я не могу использовать синтаксис блокировки (объекта), потому что мы используем веб-ферму с несколькими серверами приложений, которые не используют статические переменные.