代码之家  ›  专栏  ›  技术社区  ›  Slauma

读取、递增和写回在多个用户中唯一的计数器(在EF4中)

  •  2
  • Slauma  · 技术社区  · 15 年前

    我有一个数据库表和一个对应的实体类(带有更改跟踪代理的POCO),其中一个成员充当计数器:

    class MyEntity
    {
        public virtual int ID { get; set; }
        public virtual int Counter { get; set; }
    }
    

    在我的web应用程序中有一个函数,它必须通过ID获取这个实体,读取 Counter (然后用于分配给其他对象),将其递增并将实体写回数据库,如下所示:

    public int GetNewCounter(int ID)
    {
        int newCounter = 0;
        using (MyObjectContext ctx = new MyObjectContext())
        {
            MyEntity ent = ctx.MyEntities.Where(e => e.ID == ID).Single();
            ++ent.Counter;
            newCounter = ent.Counter;
            ctx.SaveChanges();
        }
        return newCounter;
    }
    // newCounter is now used for other stuff
    

    两个或两个以上的用户可以同时执行此操作(使用相同ID的实体),我必须确保他们不读取和使用相同的计数器(因此,在第一个用户将递增的计数器存储回数据库之前,第二个用户不应能够获取计数器)。

    用实体框架(ef4)实现这个需求我有什么选择?

    我对sqlserver和Entity框架中的并发特性和思想非常陌生,希望能在这个特定问题上得到正确的帮助。

    2 回复  |  直到 15 年前
        1
  •  1
  •   ThatSteveGuy    15 年前

    我很确定TransactionScope(使用事务)会锁定表,但是您可能需要确定这就是您想要的(表锁)。您还可以查看ConcurrencyMode=“fixed”,尽管我不确定这是否会让您完全了解您要查找的内容。

        2
  •  0
  •   Slauma    15 年前

    我试过用 ConcurrencyMode fixed 对于 Counter 中的属性 MyEntity

    public int GetNewCounter(int ID)
    {
        int newCounter = 0;
        using (MyObjectContext ctx = new MyObjectContext())
        {
            MyEntity ent = ctx.MyEntities.Where(e => e.ID == ID).Single();
            int iRetries = 0;
            bool success = false;
    
            do
            {
                try
                {
                    ++ent.Counter;
                    newCounter = ent.Counter;
                    ctx.SaveChanges();
                    success = true;
                }
                catch (OptimisticConcurrencyException)
                {
                    ctx.Refresh(RefreshMode.StoreWins, ent);
                    ++iRetries;
                    if (iRetries == 3) // give up after 3 retries
                        throw;
                }
            } while (!success);
        }
        return newCounter;
    }