我正在尝试了解实体框架的工作原理。据我所知,EF SaveChanges基本上是事务更新的包装器。我也明白,如果需要,你可以在TransactionScope中包装两个上下文。
我正在使用Code First方法。
我不明白我将如何进行像
这样的更新UPDATE Inventory SET Available = Available - 1 WHERE Available > 0
换句话说 - 在进行更新之前,如何确保至少有X个可用库存?
我想我可以编写查看产品库存的代码,并验证是否有足够的库存来完成购买:
if (Product.Inventory - quantityToPurchase < 0) throw new Exception(..)
但是,在两个客户同时尝试购买并且每个客户从数据库中获取的对象声称库存中有2个项目的情况下呢?我上面的逻辑不会理解。
如何确保SaveChanges()方法仅提交对象IF的更改,并且只有(Available - quantity)
大于0?
答案 0 :(得分:1)
在通过覆盖SaveChanges方法保存实体时,需要执行此检查:
public override int SaveChanges()
{
var entities = ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added ||
e.State == EntityState.Modified)
.Select(e => e.Entity())
.OfType<YourEntityType();
foreach (var entity in entities)
{
// Run business rule
}
return base.SaveChanges();
}
答案 1 :(得分:1)
实体框架默认使用Optimistic Concurrency。我在原帖中描述的内容在EF中称为悲观并发。有两个属性可用于实现此目的。
首先是Timestamp
,它会在表格中创建一个rowversion
列。 EF将自动检测到这一点,并始终在更新中添加where
子句,将实体的属性值与数据库中列的值进行比较。仅当两者匹配时,update
语句才会成功。 rowversion
列会自动由服务器递增。这可确保您始终更新内存中的相同数据(在POCO中)。如果其他人在您获取该行之后以及更新之前更改了该行,则更新将失败。
第二个是ConcurrencyCheck
,它与Timestamp
相似。它将导致POCO属性的值包含在where
子句中。最大的区别是它不会像rowversion
那样更新此列。