2012-11-23 33 views
5

Bir .NET + EF uygulaması yazdım. Her şey tek bir iş parçacığında iyi çalışır. Birden fazla iş parçacığında - başka bir hikaye.Varlık Çerçeve eş zamanlılık yenileme ve güncelleştirme

EF neslimde tam sayı sayacım var. Bu özellik "Concurrency Mode = Fixed" olarak işaretlenmiştir. Temel olarak, yapmaya çalıştığım şey bu sayıcıyı çeşitli iş parçacıklarında güncelleştirmektir. Bu işlem gibi :

this.MyCounter -= 1; 

o eşzamanlılık modu değiştirildi Çünkü üzere "Sabit", ben zaten değiştirecek bir özellik güncellemek tring olduğumda - Bir OptimisticConcurrencyException atılır. Bu eşzamanlılık sorunlarını çözmek için

, ben bu kodu kullanıyorum:

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); 
    } 
} 

Bu kodun sonucu sonsuz (ya da belki onun sadece bakar gibi) döngü. Her bir this.UsageAmount -= 1 çağrısı, OptimisticConcurrencyException'u atıyor, bu da döngünün tekrar çalışmasına neden oluyor.

Benim EntityContainer.Instance.Entities Benim bir EF bağlamı PER GERÇEK sağlayan bir singleton sınıfıdır. Bu, her iş parçacığının benzersiz bir içeriğe sahip olduğu anlamına gelir. Kod:

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; 
      } 
     } 
    } 

BTW, Entities.Refresh yöntemleri çağrıldıktan sonra - işe yarıyor gibi görünüyor (nesne durumu Değişmeyen ve Propery değeri veritabanında mevcut tam olarak ne).

Bu eşzamanlılık sorununu nasıl çözebilirim?

+1

Eğer 'EntityContainer.Instance.Entities' söz Singleton sınıf için kod gönderir misiniz? - Sadece "iş parçacığı başına bir EF içeriği" sağladığınız bölüm. – lukiffer

+0

EntityContainer.Instance.Entities kodu gönderiye eklenir. – No1Lives4Ever

+0

* Her * çağrısı attığınız zaman, bu, her zaman veritabanına her zaman yenildikleri için güncelleme yapmaktan kaçınan bazı konulara inebilir mi? DB'deki değer gerçekten değişiyor mu? – shambulator

cevap

1

Bunu, veritabanımda kaydettiğim semafor kullanarak çok örnekli bir masmavi webrole için yazdığım bazı kodlarda çözdüm. İşte semaforu almak için kullandığım kod. Rakip örneklerim arasında gerçekleşen yarış koşullarını ele almak için fazladan bir kod eklemem gerekiyordu. Ayrıca semaforumun bazı hatalar nedeniyle kilitli kalması durumunda bir zaman tahliyesi ekliyorum.

 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 ... 

Benim semafor modeli şöyle görünür:

using System.ComponentModel.DataAnnotations; 

public class Semaphore : MyEntityBase //contains audit properties 
{ 

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

    public string Description { get; set; } 
} 
İlgili konular