Предполагая, что существует следующие C# POCO:C# asp.net селективная блокировка между несколькими экземплярами
public class Gift
{
public int Id { get; set; }
public string Owner { get; set; }
}
И следующие услугами:
public class GiftClaimService
{
private ISomeRepository _someRepository; // Going to be injected or whatever
public bool ClaimGift(int giftId, string myName)
{
var gift = _someRepository.Get(giftId);
if (gift != null && gift.Owner == null)
{
gift.Owner = myName;
_someRepository.Save(gift);
return true;
}
return false;
}
}
Я надеюсь, что это легко unterstand. Любой пользователь, вызывающий «ClaimGift» с правильным идентификатором, может требовать подарок, в этом случае его имя ставится как Владелец подарка. Используемый репозиторий выходит за рамки, не имеет значения, есть ли база данных и т. Д.
Теперь этот сценарий, очевидно, имеет некоторые проблемы с параллелизмом. Два или более пользователя, имеющие собственные экземпляры GiftClaimService
и ISomeRepository
, могут попытаться получить подарок практически в одно и то же время, вызывая некоторые проблемы с этим методом (например, переопределение владельца несколько раз, сохранение неправильного результата или того, что вы можете себе представить).
Я хотел бы заблокировать это, создав «глобальный» объект блокировки, который не позволит другим (другим потокам/экземплярам и т. Д.) Получить тот же замок, ограниченный типом (Gift
), и это Id
. В этом случае это может работать «одновременно» (хотя и не в том же экземпляре) для разных идентификаторов.
Блокировка освобождается его владельцем после внесения изменений (путем вызова Save
в репозитории). Для других он ведет себя как обычные блокировки: обработка выполняется по этой команде. Новый метод будет выглядеть следующим образом:
public bool ClaimGift(int giftId, string myName)
{
var result = false;
// Lock it up (Pseudo-command)... I have no idea how this could work?
lock(typeof(Gift), giftId)
{
var gift = _someRepository.Get(giftId);
if (gift != null && gift.Owner == null)
{
gift.Owner = myName;
_someRepository.Save(gift);
result = true;
}
}
return result;
}
Это, как я хочу это может выглядеть, есть ли общий метод/шаблон, как решить эту проблему?
просто добавить столбец временных меток на подарочной таблице, а затем EF будет проверять при обновлении, если это значение столбцов было изменено или нет, и вы получите хороший исключение. – hazimdikenli
@hazimdikenli OK Я уже реализовал такой оптимистичный параллелизм в EF раньше, но это совсем не то же самое, это о попытке предотвратить этот сценарий вообще, плюс репозиторий не является ни EF, ни SQL Server (в настоящее время его MongoDB, но Я не хочу, чтобы это решение было специфичным для базы данных) – thmshd
о добавлении глобального массива/списка претензий, выполняемых с идентификатором подарка, и доступа к нему с помощью объекта-замка. – hazimdikenli