Следующий сценарий, я бы сказал, довольно распространенный, и хотя я знаю один способ его решения, но ему не хватает элегантности.
Пример, который я привожу, основан на https://github.com/sharparchitecture/Sharp-Architecture-Cookbook.
Приложение, которое я кодирую, является приложением ASP.NET MVC и должно поддерживать несколько пользователей, работающих над одним и тем же объектом.
Следующий сценарий - крайний случай, но, тем не менее, действительный.
Допустим, у вас есть два пользователя, работающие над одним и тем же объектом, и возможность обновления строки дБ зависит от значения конкретного поля. Чтобы сделать его более конкретным, скажем, у вас есть продукт, а для простоты этот продукт имеет поля «Имя» и «Количество в запасе».
Предположим, что изначально существует 10 наименований Продукта, а Пользователь1 и Пользователь2 хотят купить этот продукт. Когда обоим пользователям представлена первоначальная форма, им сообщают, что на складе имеется 10 таких товаров. Теперь пользователь 1 покупает все 10 товаров, а пользователь 2 пьет кофе. Таким образом, транзакция User1 проходит без проблем.
Затем Пользователь2 возвращается за своим кофе, полагая, что на складе еще есть 10 предметов. Поэтому он пытается купить 1, но он не должен этого делать, так как на складе нет товаров.
Таким образом, эта проблема может быть решена с помощью проверки ASP.NET DataAnnotations, и это поймает большинство случаев. Однако, в нашем крайнем случае, скажем, что User1 и User2 выполняют одну и ту же операцию, но в течение доли секунды, так что, когда User2 отправляет форму, он проходит проверку ASP.NET, но к тому времени, когда он попадает на уровень постоянства, Количество в запасе равно 0.
Решением этой проблемы является выполнение проверки в самый последний момент, насколько это возможно, то есть непосредственно перед вызовом метода Update.
Теперь немного кода.
public ProductModel CreateOrUpdate(ProductModel productModel)
{
var currentProductModel = Get(productModel.Id);
var currentQuantityInStock = currentProductModel.QuantityInStock;
if(currentProductModel.QuantityInStock !=0 && productModel.QuantityInStock >= currentQuantityInStock )
{
currentProductModel.QuantityInStock= productModel.QuantityInStock;
currentProductModel.Name = productModel.Name;
this.productModelRepository.SaveOrUpdate( currentProductModel );
return productModel;
}
else
{
//Raise an exception
}
}
Теперь тот факт, что я звоню:
var currentProductModel = Get(productModel.Id);
означает, что если бы я просто сделал это:
this.productModelRepository.SaveOrUpdate( productModel );
вызовет исключение:
другой объект с тем же значением идентификатора уже был связан с сеансом: 1
Следовательно, мне нужно скопировать все значения из productModel в currentProductModel. Это нормально, когда я использую что-то вроде Automapper, но мне все равно кажется, что я чувствую, что должен просто сохранять productModel без необходимости переноса данных из одного объекта в другой.
Более того, необходимость выполнять одну и ту же проверку дважды, один раз с использованием DataAnnotation, а другой - непосредственно перед обновлением, нарушает принцип DRY.
Дело в том, что я чувствую, что мне не хватает уловки, но я не совсем знаю, с чего начать и что расследовать.
Для меня это простая проблема, но придумать хорошее элегантное решение - это нечто другое. Итак, вопрос в том, как вы справлялись с этим простым случаем в прошлом? Я обдумываю это?