2012-08-16 28 views
7

मुझे कुछ दिनों के लिए इस के आसपास अपना सिर लेने की कोशिश की गई है और काम की इकाई के आसपास और ट्रांज़ेक्शनस्कोप के आसपास बहुत सारे ट्यूटोरियल हैं लेकिन मुझे कुछ भी नहीं मिल रहा है जो इस बारे में बात करता है दो एक साथ। किसी भी मदद की बहुत सराहना की!डाटाबेस लेनदेन के साथ कार्य पैटर्न का यूनिट

मैं यूनिट ऑफ वर्क पैटर्न और प्रति प्रकार एक भंडार के साथ इकाई फ्रेमवर्क का उपयोग कर रहा हूं। नीचे दिए गए सरल कोड के अनुसार मेरे पास एक सदस्य और सदस्यता परिभाषा इकाई है। मैं एक सदस्यता इकाई बनाना चाहता हूं जो सदस्यता को ऑब्जेक्ट बनाते समय दो लेकिन से लिंक करे, मैं कुछ व्यावसायिक तर्क के आधार पर अधिकतम मूल्य के लिए डीबी से पूछताछ करना चाहता हूं। इसलिए, मुझे किसी अन्य थ्रेड को डीबी में मान बढ़ाने से पहले किसी अन्य थ्रेड को डीबी में वापस करने से रोकने के लिए किसी प्रकार के डीबी लेनदेन का उपयोग करने की आवश्यकता है।

अगर मैं संग्रहीत procs प्रयोग किया गया था, यह बिल्कुल स्पष्ट हो जाएगा, लेकिन मैं कैसे का उपयोग कर शुद्ध सी # यह करने के लिए पता नहीं कर सकते हैं ...

कोड नीचे डुप्लिकेट MembershipNumbers साथ डेटाबेस में 100 सदस्यता संस्थाओं बनाता है । मुझे यह सुनिश्चित करने के लिए लेनदेन का उपयोग करने के लिए इस उपयोग को प्राप्त करने की आवश्यकता है कि सी # कोड में उत्पन्न सभी सदस्यता संख्या अद्वितीय हैं।

class Program 
{ 
    static void Main(string[] args) 
    { 
     var p = new Program(); 
     p.Go();; 
    } 

    public void Go() 
    { 
     long memberId; 
     long membershipDefId; 

     using(var unitOfWork = new UnitOfWork()) 
     { 
      // Setup - create test club and member entities 

      var testUsername = ("TestUserName" + Guid.NewGuid()).Substring(0, 29); 
      var member = new Member() 
          { 
           UserName = testUsername 
          }; 

      var testmemebrshpDefName = ("TestMembershipDef" + Guid.NewGuid()).Substring(0, 29); 
      var membershipDefinition = new ClubMembershipDefinition() 
      { 
       ClubId = 1, 
       Name = testmemebrshpDefName 
      }; 

      unitOfWork.MemberRepository.Add(member); 
      unitOfWork.MembershipDefinitionRepository.Add(membershipDefinition); 

      unitOfWork.Save(); 

      memberId = member.Id; 
      membershipDefId = membershipDefinition.Id; 
     } 

     Task[] tasks = new Task[100]; 

     // Now try to add a membership to the Member object, linking it to the test Club's single Club Definition 
     for (int i = 0; i < 100; i++) 
     { 
      var task = new Task(() => CreateMembership(memberId, membershipDefId)); 
      tasks[i] = task; 
      task.Start(); 
     } 
     Task.WaitAll(tasks); 
    } 

    private void CreateMembership(long memberId, long membershipDefId) 
    { 
     using (var unitOfWork = new UnitOfWork()) 
     { 
      var member = unitOfWork.MemberRepository.GetById(memberId); 
      var membershipDef = unitOfWork.MembershipDefinitionRepository.GetById(membershipDefId); 

      var membership = new ClubMembership() 
            { 
             ClubMembershipDefinition = membershipDef 
            }; 

      membership.MembershipNumber = (unitOfWork.MembershipRepository.GetMaxMembershipNumberForClub(membershipDef.ClubId) ?? 0) + 1; 

      member.ClubMemberships.Add(membership); 
      unitOfWork.Save(); 
     } 
    } 

} 

public class UnitOfWork : IUnitOfWork, IDisposable 
{ 
    internal ClubSpotEntities _dbContext = new ClubSpotEntities(); 
    internal MemberRepository _memberRepository; 
    internal MembershipRepository _membershipRepository; 
    internal MembershipDefinitionRepository _membershiDefinitionpRepository; 

    public MemberRepository MemberRepository 
    { 
     get 
     { 
      if (_memberRepository == null) 
       _memberRepository = new MemberRepository(_dbContext); 

      return _memberRepository; ; 
     } 
    } 

    public MembershipRepository MembershipRepository 
    { 
     get 
     { 
      if (_membershipRepository == null) 
       _membershipRepository = new MembershipRepository(_dbContext); 

      return _membershipRepository; ; 
     } 
    } 

    public MembershipDefinitionRepository MembershipDefinitionRepository 
    { 
     get 
     { 
      if (_membershiDefinitionpRepository == null) 
       _membershiDefinitionpRepository = new MembershipDefinitionRepository(_dbContext); 

      return _membershiDefinitionpRepository; ; 
     } 
    } 

    public virtual int Save() 
    { 
     return _dbContext.SaveChanges(); 

    } 

    private bool _disposed = false; 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!this._disposed) 
     { 
      if (disposing) 
      { 
       _dbContext.Dispose(); 
      } 
     } 
     this._disposed = true; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
} 

public class MembershipRepository 
{ 
    ClubSpotEntities _dbContext = new ClubSpotEntities(); 

    public MembershipRepository(){} 

    public MembershipRepository(ClubSpotEntities dbContext) 
    { 
     _dbContext = dbContext; 
    } 

    public IEnumerable<ClubMembership> GetAll() 
    { 
     return _dbContext.Set<ClubMembership>().ToList<ClubMembership>(); 
    } 

    public ClubMembership GetById(long id) 
    { 
     return _dbContext.ClubMemberships.First(x => x.Id == id); 
    } 

    public long? GetMaxMembershipNumberForClub(long clubId) 
    { 
     return _dbContext.ClubMemberships.Where(x => x.ClubMembershipDefinition.ClubId == clubId).Max(x => x.MembershipNumber); 
    } 

    public ClubMembership Add(ClubMembership entity) 
    { 
     return _dbContext.Set<ClubMembership>().Add(entity); 
    } 

    public void Delete(ClubMembership membership) 
    { 
     _dbContext.Set<ClubMembership>().Remove(membership); 
    } 

    public void Save() 
    { 
     _dbContext.SaveChanges(); 
    } 
} 


public partial class ClubMembership 
{ 
    public long Id { get; set; } 
    public long MembershipDefId { get; set; } 
    public Nullable<long> MemberId { get; set; } 
    public Nullable<long> MembershipNumber { get; set; } 

    public virtual ClubMembershipDefinition ClubMembershipDefinition { get; set; } 
    public virtual Member Member { get; set; } 
} 

public partial class ClubMembershipDefinition 
{ 
    public ClubMembershipDefinition() 
    { 
     this.ClubMemberships = new HashSet<ClubMembership>(); 
    } 

    public long Id { get; set; } 
    public long ClubId { get; set; } 
    public string Name { get; set; } 

    public virtual ICollection<ClubMembership> ClubMemberships { get; set; } 
} 

public partial class Member 
{ 
    public Member() 
    { 
     this.ClubMemberships = new HashSet<ClubMembership>(); 
    } 

    public long Id { get; set; } 
    public string UserName { get; set; } 

    public virtual ICollection<ClubMembership> ClubMemberships { get; set; } 
} 
+0

क्या आप वाकई एक लेनदेन पर्याप्त हैं? –

+0

आप एंटीटी फ्रेमवर्क के माध्यम से संग्रहीत प्रक्रियाओं को कॉल कर सकते हैं, तो आपके पास – podiluska

+0

पर जो काम है, उससे जटिल क्यों हो, मैं इस सवाल को एक सामान्य सामान्य के रूप में देखता हूं: इस तरह की प्रणाली की जटिलता को कैसे कम करें ताकि हम सिस्टम की लेनदेन संबंधी शुद्धता के बारे में सोच सकें । इस मामले में, हम MAX() के लिए समस्या का समाधान कर सकते हैं, लेकिन हम कैसे सुनिश्चित कर सकते हैं कि सिस्टम अपेक्षित रूप से काम करता है, डेडलॉक नहीं करता है, और धीरे-धीरे नहीं चलता है। एक क्रमिक लेनदेन के साथ भी, आप यह सुनिश्चित नहीं कर सकते कि समानांतर में संचालन चलाते समय आपका सिस्टम अच्छा व्यवहार करता है। – Steven

उत्तर

2

आप नए यूनिटऑफवर्क को तुरंत चालू करते समय लेनदेन के दायरे बना सकते हैं, और इसे पूरा होने पर प्रतिबद्ध कर सकते हैं। यह न पूर्ण उदाहरण के:

class UnitOfWork 
{ 
    ClubSpotEntities _dbContext; 
    TransactionScope _transaction; 

    public UnitOfWork() 
    { 
     _dbContext = new ClubSpotEntities(); 
     _transaction = new TransactionScope(); 
    } 

    public void Complete() 
    { 
     _dbContext.SaveChanges(); 
     _transaction.Complete(); 
    } 

    ... 
} 

युपीडी: स्टीवन के रूप में कहा था कि यह आप समस्या का समाधान नहीं है। और UnitOfWork आपकी मदद नहीं कर सकता, TransactionScope इस मामले में एक समाधान नहीं खोना। ईएफ निराशावादी ताले का समर्थन नहीं करता है जिसे आप उपयोग करना चाहते हैं, लेकिन आप इसे solution आज़मा सकते हैं।

+1

लेनदेन के अंदर चलना कोई हल नहीं करता है ओपी समस्या, चूंकि दो समांतर संचालन अभी भी एक ही 'सदस्यता संख्या' के साथ दो सदस्यों को सम्मिलित कर सकते हैं (जहां एक ऑपरेशन संभवतः असफल हो जाएगा)। – Steven

+0

आप धारावाहिक अलगाव स्तर का उपयोग कर सकते हैं। बेशक यह डेडलॉक्स को उकसा सकता है, लेकिन यह कार्यान्वयन के मामले में है और ईएफ या संग्रहीत प्रक्रियाओं को चुनने पर निर्भर नहीं है। अगर डेडलॉक्स दुर्लभ हैं तो आप ऑपरेशन दोहराने की कोशिश कर सकते हैं। –

+1

'सरलीज़ेबल' लेनदेन में चलते समय, SQL सर्वर भी पंक्तियों को लॉक करेगा जो पढ़ रहे हैं। हालांकि, जब आपकी क्वेरी केवल एक इंडेक्स पर चलती है (जैसे ओपी की 'MAX()' क्वेरी कर सकती है), केवल वह इंडेक्स लॉक हो जाएगा, न कि तालिका स्वयं। इसलिए हालांकि इस मामले में serializable 'CreateMembership' संचालन को क्रमबद्ध करने में मदद करेगा, फिर भी यह अन्य परिचालनों के संयोजन के साथ विफल हो सकता है। – Steven

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^