2012-09-24 10 views
6

जोड़ने के लिए SaveChanges का उपयोग करके ऑडिट लॉगर जोड़ने के लिए EF में SaveChanges को सीधे ओवरराइड करना लगता है। ऑडिट गुणों (बनाई गई, बनाई गई, अद्यतन, अपडेटेडबी) को सेट करने के लिए ApplyAuditLogging विधि देखें।एंटिटी फ्रेमवर्क 5 ऑडिट लॉग

public override int SaveChanges() 
    { 
     var autoDetectChanges = Configuration.AutoDetectChangesEnabled; 

     try 
     { 
      Configuration.AutoDetectChangesEnabled = false; 
      ChangeTracker.DetectChanges(); 
      var errors = GetValidationErrors().ToList(); 
      if(errors.Any()) 
      { 
       throw new DbEntityValidationException("Validation errors were found during save: " + errors); 
      } 

      foreach (var entry in ChangeTracker.Entries().Where(e => e.State == EntityState.Added || e.State == EntityState.Modified)) 
      { 
       ApplyAuditLogging(entry); 
      } 

      ChangeTracker.DetectChanges(); 

      Configuration.ValidateOnSaveEnabled = false; 

      return base.SaveChanges(); 
     } 
     finally 
     { 
      Configuration.AutoDetectChangesEnabled = autoDetectChanges; 
     } 
    } 

    private static void ApplyAuditLogging(DbEntityEntry entityEntry) 
    { 

     var logger = entityEntry.Entity as IAuditLogger; 
     if (logger == null) return; 

     var currentValue = entityEntry.Cast<IAuditLogger>().Property(p => p.Audit).CurrentValue; 
     if (currentValue == null) currentValue = new Audit(); 
     currentValue.Updated = DateTime.Now; 
     currentValue.UpdatedBy = "???????????????????????"; 
     if(entityEntry.State == EntityState.Added) 
     { 
      currentValue.Created = DateTime.Now; 
      currentValue.CreatedBy = "????????????????????????"; 
     } 
    } 

समस्या यह है कि कैसे खिड़कियों उपयोगकर्ता लॉगऑन/उपयोगकर्ता नाम वस्तु की UpdatedBy और CreatedBy गुण सेट करने के लिए है? इसलिए मैं इसका उपयोग नहीं कर सका!

इसके अलावा, एक और मामले में मैं अपने संपर्क में स्वचालित रूप से एक नया कॉलहैतिहासिक रिकॉर्ड जोड़ना चाहता था; जब भी संपर्क संशोधित होता है, तो बाल तालिका CallHistory में एक नया रिकॉर्ड जोड़ा जाना चाहिए। तो मैंने इसे रिपोजिटरी के InsertOrUpdate में किया लेकिन यह गंदा लगता है, अगर मैं इसे उच्च स्तर पर कर सकता तो अच्छा होगा क्योंकि अब मुझे वर्तमान उपयोगकर्ता को डेटाबेस से सेट करना होगा। फिर यहां समस्या यह है कि मुझे उपयोगकर्ता को कॉलहाइस्ट्री रिकॉर्ड (SalesRep = उपयोगकर्ता) बनाने के लिए डेटाबेस से लाने की आवश्यकता है।

ContactRepository.SetCurrentUser(User).InsertOrUpdate(contact) 
:

मेरी भंडार में कोड अब 2 बातें करता है, 1, यह वस्तु जब यह या बनाया अद्यतन और, 2 है पर एक लेखा परीक्षा प्रवेश बनाई गई, यह भी एक CallHistory प्रवेश जब भी संपर्क अद्यतन किया जाता है बनाया

आदेश के लिए भंडार संदर्भ में उपयोगकर्ता के लिए में:

var prop = typeof(T).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); 

    if (prop.GetValue(entity, null).ToString() == "0") 
    { 
     // New entity 
     _context.Set<T>().Add(entity); 
     var auditLogger = entity as IAuditLogger; 
     if (auditLogger != null) 
      auditLogger.Audit = new Audit(true, _principal.Identity.Name); 
    } 
    else 
    { 
     // Existing entity 
     _context.Entry(entity).State = EntityState.Modified; 
     var auditLogger = entity as IAuditLogger; 
     if (auditLogger != null && auditLogger.Audit != null) 
     { 
      (entity as IAuditLogger).Audit.Updated = DateTime.Now; 
      (entity as IAuditLogger).Audit.UpdatedBy = _principal.Identity.Name; 
     } 

     var contact = entity as Contact; 
     if (_currentUser != null) 
      contact.CallHistories.Add(new CallHistory 
       { 
        CallTime = DateTime.Now, 
        Contact = contact, 
        Created = DateTime.Now, 
        CreatedBy = _currentUser.Logon, 
        SalesRep = _currentUser 
       }); 
    } 
} 

वहाँ एक रास्ता किसी भी तरह DbContext में SaveChanges ओवरराइड में खिड़कियों उपयोगकर्ता सुई है और वहाँ भी से एक उपयोगकर्ता को लाने के लिए एक रास्ता है विंडोज़ लॉगऑन आईडी पर आधारित डेटाबेस इसलिए मैं साल सेट कर सकता हूं मेरे CallHistory पर esRep (ऊपर कोड देखें)?

यहाँ MVC अनुप्रयोग पर नियंत्रक पर मेरी लड़ाई है:

[HttpPost] 
public ActionResult Create([Bind(Prefix = "Contact")]Contact contact, FormCollection collection) 
{ 
    SetupVOs(collection, contact, true); 
    SetupBuyingProcesses(collection, contact, true); 

    var result = ContactRepository.Validate(contact); 

    Validate(result); 

    if (ModelState.IsValid) 
    { 
     ContactRepository.SetCurrentUser(User).InsertOrUpdate(contact); 
     ContactRepository.Save(); 
     return RedirectToAction("Edit", "Contact", new {id = contact.Id}); 
    } 

    var viewData = LoadContactControllerCreateViewModel(contact); 

    SetupPrefixDropdown(viewData, contact); 

    return View(viewData); 
} 

उत्तर

6

खैर, यह बस अपने लेखा परीक्षा कोड के भीतर से HttpContext.Current.User.Identity.Name तक पहुँचने के लिए है करने के लिए सरल और आलसी तरीका । हालांकि, यह System.Web। * पर निर्भरता बनाएगा, जो संभवतया आप नहीं चाहते हैं यदि आपके पास अच्छी तरह से टियर किए गए एप्लिकेशन हैं (और यदि आप वास्तविक अलग-अलग स्तरों का उपयोग कर रहे थे तो यह काम नहीं करेगा)।

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

एक बेहतर तरीका यह है कि आप अपने डीबीकॉन्टेक्स्ट में _currentUser प्रॉपर्टी को जोड़ दें और इसे पास करने के लिए एक कन्स्ट्रक्टर का उपयोग करें। फिर जब आप संदर्भ बनाते हैं, तो आप उस समय उपयोगकर्ता को पास कर देते हैं। दुर्भाग्य से, आप वास्तव में निर्माता से डेटाबेस में उपयोगकर्ता को नहीं देख सकते हैं।

लेकिन आप केवल संपर्क आईडी को सहेज सकते हैं और पूरे संपर्क के बजाय इसे जोड़ सकते हैं। आप संपर्क पहले से मौजूद होना चाहिए।

+3

सैमकाउंटनाम बदलना योग्य नहीं है इसलिए एक अच्छा पहचानकर्ता नहीं है। मैं सक्रिय निर्देशिका guid का उपयोग करता हूं कि सभी वस्तुओं को इसके बजाय मिलता है – meffect

0

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

1

मुझे पता है कि यह एक देर का जवाब है, लेकिन मैं इस सवाल पर बस stubmled। मेरे पास एक बहुत ही समान उपयोग मामला था।

var auditUsername = Current.User.Identity.Name; 
var auditDate = DateTime.Now; 

और वर्तमान वर्ग:

public class Current 
    { 
     public static IPrincipal User 
     { 
      get 
      { 
       return System.Threading.Thread.CurrentPrincipal; 
      } 
      set 
      { 
       System.Threading.Thread.CurrentPrincipal = value; 
      } 

     } 
    } 

इस प्रक्रिया की खिड़कियों उपयोगकर्ता, या उपयोगकर्ता कि ASP.NET applicatoin में प्रवेश होने देता है इस प्रकार हमने कर दिखाया। अधिक पढ़ने के लिए: http://www.hanselman.com/blog/SystemThreadingThreadCurrentPrincipalVsSystemWebHttpContextCurrentUserOrWhyFormsAuthenticationCanBeSubtle.aspx

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