c# - Entity Framework 并发刷新和更新

标签 c# entity-framework concurrency refresh updates

我编写了一个 .NET + EF 应用程序。在单线程上一切正常。在多线程上 - 这是另一回事了。

在我的 EF 对象中,我有一个整数计数器。此属性标记为“Concurrency Mode = Fixed”。基本上,我要做的是在多个线程上更新此计数器。 喜欢这个操作:

this.MyCounter -= 1;

因为它的并发模式已更改为“固定”,所以当我尝试更新已更改的属性时 - 抛出 OptimisticConcurrencyException

为了解决这个并发问题,我使用了这段代码:

while (true)
{
    try
    {
        this.UsageAmount -= 1; // Change the local EF object value and call SaveChanges().
        break;
    }
    catch (OptimisticConcurrencyException)
    {
        Logger.Output(LoggerLevel.Trace, this, "concurrency conflict detected.");
        EntityContainer.Instance.Entities.Refresh(RefreshMode.StoreWins, this.InnerObject);
    }
}

这段代码的结果是一个无限循环(或者可能只是看起来像)循环。每次调用 this.UsageAmount -= 1 都会抛出一个 OptimisticConcurrencyException,这会导致循环再次运行。

我的 EntityContainer.Instance.Entities 是一个单例类,它为每个线程提供一个 EF 上下文。这意味着每个线程都有一个唯一的上下文。代码:

public sealed class EntityContainer
    {
        #region Singlethon Implemantation
        private static Dictionary<Thread, EntityContainer> _instance = new Dictionary<Thread,EntityContainer> ();
        private static object syncRoot = new Object();
        public static EntityContainer Instance
        {
            get
            {
                if (!_instance.ContainsKey(Thread.CurrentThread))
                {
                    lock (syncRoot)
                    {
                        if (!_instance.ContainsKey(Thread.CurrentThread))
                            _instance.Add(Thread.CurrentThread, new EntityContainer());
                    }
                }
                return _instance[Thread.CurrentThread];
            }
        }
        private EntityContainer()
        {
            Entities = new anticopyEntities2();
        }
        #endregion

        anticopyEntities2 _entities;
        public anticopyEntities2 Entities
        {
            get
            {
                //return new anticopyEntities2();
                return _entities;
            }
            private set
            {
                _entities = value;
            }
        }
    }

顺便说一句,在调用 Entities.Refresh 方法后 - 看起来它正在工作(对象状态未更改,属性值正是数据库中存在的值)。

如何解决这个并发问题?

最佳答案

我通过使用保存在数据库中的信号量为多实例 azure webrole 编写的一些代码解决了这个问题。这是我用来获取信号量的代码。我不得不添加一些额外的代码来处理我的竞争实例之间发生的竞争条件。我还添加了一个时间释放,以防我的信号量由于某些错误而被锁定。

        var semaphore = SemaphoreRepository.FetchMySemaphore(myContext);
        var past = DateTime.UtcNow.AddHours(-1);

        //check lock, break if in use.  Ignor if the lock is stale.
        if (semaphore == null || (semaphore.InUse && (semaphore.ModifiedDate.HasValue && semaphore.ModifiedDate > past)))
        {
            return;
        }

        //Update semaphore to hold lock
        try
        {
            semaphore.InUse = true;
            semaphore.OverrideAuditing = true;
            semaphore.ModifiedDate = DateTime.UtcNow;
            myContext.Entry(semaphore).State = EntityState.Modified;
            myContext.SaveChanges();
        }
        catch (DbUpdateConcurrencyException)
        {
            //concurrency exception handeling another thread beat us in the race.  exit
            return;
        }
        catch (DBConcurrencyException)
        {
            return;
        }

        //Do work here ...  

我的信号量模型如下所示:

using System.ComponentModel.DataAnnotations;

public class Semaphore : MyEntityBase //contains audit properties
{

    [Required]
    [ConcurrencyCheck]
    public bool InUse { get; set; }

    public string Description { get; set; }
}

关于c# - Entity Framework 并发刷新和更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13524619/

相关文章:

c# - Postgres 数据库在 ADO.NET 实体数据模型中不可用

java - 我应该将共享静态变量指定为 volatile 吗?

java - 寻找等待对象

c# - 具有可动态切换数据类型的文本框的 MVC 4 客户端验证

c# - 比较 2 个图像的焦点

C#使用 Entity Framework 使用多个应用程序连接单个数据库

c# - EF 上的 Find() 强制我在通用方法的调用中指定类型

java - 带有线程池的嵌套循环

c# - 响应.Write(对象)

C# https 请求总是隧道到服务器,但 Java 只有一次