下面的场景是,我会说很常见,虽然我知道解决它的一种方法,但它缺乏优雅。
我给出的示例基于https://github.com/sharparchitecture/Sharp-Architecture-Cookbook。
我正在编写的应用程序是一个 ASP.NET MVC 应用程序,并且必须支持多个用户在同一个对象上工作。
以下场景是一个边缘案例,但仍然是一个有效的案例。
假设您有两个用户在处理同一个对象,并且 dB 行是否可以更新取决于特定字段的值。为了使其更具体,假设您有一个产品,并且为了简单起见,该产品具有“名称”和“数量库存”字段。
假设最初有 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 原则。
关键是我觉得我错过了一个技巧,但不知道从哪里开始以及调查什么。
这对我来说是一个简单的问题,但想出一个很好的优雅解决方案是另一回事。所以问题是你过去是如何处理这个简单的案例的?这是我想太多了吗?