如何在实体框架中加入/解决多用户安全问题5

时间:2013-03-27 21:01:32

标签: entity-framework tsql

增加或减少整数字段的干净,安全的方法是什么。

我将sql server 2012与entityframework 5.x结合使用

我寻找相当于互锁的增量/减量。

1 个答案:

答案 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值的实体,并且下一个循环尝试再次递增或递减重新加载的值,直到它成功而没有并发冲突。