बहुत, बहुत मोटा अनुमान:
foreach (var property in dbEntityEntry.Entity.GetType().GetProperties())
{
DbPropertyEntry propertyEntry = dbEntityEntry.Property(property.Name);
if (propertyEntry.IsModified)
{
Log.WriteAudit("Entry: {0} Original :{1} New: {2}", property.Name,
propertyEntry.OriginalValue, propertyEntry.CurrentValue);
}
}
अगर यह वास्तव में विस्तार से काम करेगा मैं कोई सुराग नहीं है, लेकिन यह कुछ मैं पहले कदम के रूप की कोशिश करेंगे है। निस्संदेह एक संपत्ति हो सकती है जो बदल गई है, इसलिए लूप और शायद WriteAudit
की कई कॉल।
SaveChanges के अंदर प्रतिबिंब सामग्री हालांकि प्रदर्शन प्रदर्शन दुःस्वप्न बन सकती है।
संपादित
शायद यह अंतर्निहित ObjectContext
उपयोग करने के लिए बेहतर है। फिर कुछ ऐसा संभव है:
public class TestContext : DbContext
{
public override int SaveChanges()
{
ChangeTracker.DetectChanges(); // Important!
ObjectContext ctx = ((IObjectContextAdapter)this).ObjectContext;
List<ObjectStateEntry> objectStateEntryList =
ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added
| EntityState.Modified
| EntityState.Deleted)
.ToList();
foreach (ObjectStateEntry entry in objectStateEntryList)
{
if (!entry.IsRelationship)
{
switch (entry.State)
{
case EntityState.Added:
// write log...
break;
case EntityState.Deleted:
// write log...
break;
case EntityState.Modified:
{
foreach (string propertyName in
entry.GetModifiedProperties())
{
DbDataRecord original = entry.OriginalValues;
string oldValue = original.GetValue(
original.GetOrdinal(propertyName))
.ToString();
CurrentValueRecord current = entry.CurrentValues;
string newValue = current.GetValue(
current.GetOrdinal(propertyName))
.ToString();
if (oldValue != newValue) // probably not necessary
{
Log.WriteAudit(
"Entry: {0} Original :{1} New: {2}",
entry.Entity.GetType().Name,
oldValue, newValue);
}
}
break;
}
}
}
}
return base.SaveChanges();
}
}
मैंने इसे स्वयं ईएफ 4.0 में उपयोग किया है। मुझे DbContext
एपीआई में GetModifiedProperties
(प्रतिबिंब कोड से बचने की कुंजी) के लिए एक संबंधित विधि नहीं मिल रही है।
संपादित 2
महत्वपूर्ण: जब POCO संस्थाओं के साथ काम कर कोड के ऊपर शुरुआत में DbContext.ChangeTracker.DetectChanges()
कॉल करने के लिए की जरूरत है। कारण यह है कि base.SaveChanges
को यहां बहुत देर हो चुकी है (विधि के अंत में)। base.SaveChanges
आंतरिक रूप से DetectChanges
पर कॉल करता है, लेकिन क्योंकि हम पहले परिवर्तनों का विश्लेषण और लॉग इन करना चाहते हैं, हमें मैन्युअल रूप से DetectChanges
पर कॉल करना होगा ताकि ईएफ सभी संशोधित गुणों को ढूंढ सके और राज्यों को परिवर्तन ट्रैकर में सही ढंग से सेट कर सके।
संभव स्थितियों में, जहां कोड, DetectChanges
बुला बिना काम कर सकते हैं, उदाहरण के लिए Add
या Remove
तरह DbContext/DbSet तरीकों का इस्तेमाल किया जाता है, तो बाद पिछले संपत्ति संशोधन किया जाता है के बाद से इन तरीकों में भी आंतरिक रूप से DetectChanges
फोन कर रहे हैं। लेकिन अगर उदाहरण के लिए एक इकाई सिर्फ डीबी से लोड की जाती है, तो कुछ गुण बदल जाते हैं और फिर यह SaveChanges
व्युत्पन्न होता है, स्वचालित परिवर्तन पहचान base.SaveChanges
से पहले नहीं होती है, जिसके परिणामस्वरूप संशोधित गुणों के लिए लॉग प्रविष्टियां गायब होती हैं।
मैंने तदनुसार उपरोक्त कोड अपडेट किया है।
यह काम करता है, लेकिन ऐसा लगता है कि सभी गुण इस के अनुसार संशोधित हैं, जोड़ने के लिए विस्तृत लेखापरीक्षा। आगे की जांच करेंगे, लेकिन मूल प्रश्न के लिए ठीक है। मुझे लगता है कि यह मुझे जो चाहिए वह देता है। –
यह मेरे लिए काम नहीं करता है। पुराने मूल्य हमेशा खाली होते हैं। क्या यह केवल पीओसीओ और 4.1 और ऊपर काम कर रहा है? – Jonx
@ जोनक्स: हाँ, यह ईएफ 4.1 ('डीबीकॉन्टेक्स्ट') और पीओसीओ है। आप <= EF 4.0 ('ऑब्जेक्ट कॉन्टेक्स्ट') के लिए कुछ ऐसा ही कर सकते हैं, केवल अंतर यह है कि आप 'सेव चेंज' को ओवरराइट नहीं करते हैं लेकिन एक ईवेंट हैंडलर ('ऑनसेविंग चेंज' या इसी तरह लागू करते हैं, मुझे बिल्कुल याद नहीं है)। – Slauma