No1*_*ver 5 c# concurrency entity-framework refresh updates
我编写了一个.NET + EF应用程序.在一个线程上一切正常.在多个线程上 - 这是另一个故事.
在我的EF对象中,我有一个整数计数器.此属性标记为"Concurrency Mode = Fixed".基本上,我要做的是在几个线程上更新此计数器.喜欢这个操作:
this.MyCounter -= 1;
Run Code Online (Sandbox Code Playgroud)
因为它的并发模式已经改为"固定",所以当我想要更新已经改变的属性时 - 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);
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码的结果是一个无限的(或者可能只是它看起来像)循环.每次调用this.UsageAmount -= 1throw OptimisticConcurrencyException都会导致循环再次运行.
我EntityContainer.Instance.Entities是一个单例类,提供EF上下文PER THREAD.这意味着每个线程都有一个唯一的上下文.代码:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
BTW,在调用Entities.Refresh方法之后 - 看起来它正在工作(对象状态是Unchanged并且属性值正是数据库中存在的值).
我该如何解决这个并发问题?
我通过使用保存在数据库中的信号量,在为多实例 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 ...
Run Code Online (Sandbox Code Playgroud)
我的信号量模型如下所示:
using System.ComponentModel.DataAnnotations;
public class Semaphore : MyEntityBase //contains audit properties
{
[Required]
[ConcurrencyCheck]
public bool InUse { get; set; }
public string Description { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1980 次 |
| 最近记录: |