增加或减少整数字段的干净,安全的方法是什么。
我将sql server 2012与entityframework 5.x结合使用
我寻找相当于互锁的增量/减量。
答案 0 :(得分:19)
标准方法是使用乐观并发。
说,你有一个简单的实体,你想要增加或减少整数字段Counter
:
public class SomeEntity
{
public int SomeEntityId { get; set; }
public int Counter { get; set; }
}
您可以将Counter
标记为并发令牌。使用Fluent API,它是:
modelBuilder.Entity<SomeEntity>()
.Property(s => s.Counter)
.IsConcurrencyToken();
然后你可以增加或减少Counter
,例如:
public void IncDecCounter(int someEntityId, bool dec)
{
using (var context = new MyContext())
{
var someEntity = context.SomeEntities.Find(someEntityId);
if (someEntity != null)
{
bool saveFailed;
do
{
saveFailed = false;
if (dec)
--someEntity.Counter;
else
++someEntity.Counter;
try
{
context.SaveChanges();
}
catch (DbUpdateConcurrencyException e)
{
saveFailed = true;
e.Entries.Single().Reload();
}
} while (saveFailed);
}
}
}
如果加载实体时SaveChanges
的值(在此示例中为DbUpdateConcurrencyException
,可能是任何其他查询),{p> Counter
将失败并显示Find
当在数据库中执行UPDATE语句时,从数据库中的Counter
的值开始,这意味着在此期间另一个用户已经修改了Counter
。从技术上讲,这是通过生成的UPDATE语句的扩展WHERE
子句实现的,该子句不仅尝试过滤Id,还尝试过滤Counter
的旧值,基本上类似于:WHERE SomeEntityId = someEntityId AND Counter = oldCounterWhenTheEntityHasBeenLoaded
。
catch
块从数据库重新加载具有当前Counter
值的实体,并且下一个循环尝试再次递增或递减重新加载的值,直到它成功而没有并发冲突。