Log寫得好,晚上睡覺睡得好
因為目前都在用Entity Framework來處理DB,想很久Log要怎麼寫比較好
在每個Method SaveChange前多一行寫Log的動作?
這樣做非常累也不是一勞永逸的方法,只要有新的CRUD,你都必須要每個都加上去
那麼新進人員進來,不知道要加這一行來寫Log不就糗了
所以我目前想到最好的方式就是覆寫EF的SaveChange的方法
加在裡面的好處就是,只要你是用EF來CRUD,我就一定會處理的到
新進人員也不需要處理寫Log這一塊,因為已經包在底層了
所以開了3個資料表
LogEntityRef 是存放什麼資料表需要寫入Log
LogEntityField 是存放資料表的那些欄位需要寫入Log
LogEntityValue 是寫入Log的資料
三個資料表可參考下圖
那麼怎麼覆寫EF的SaveChange呢,創建一個新的Class要與EF的名稱同名
using System; using System.Collections.Generic; using System.Data.Entity; using System.Data.Entity.Core.Metadata.Edm; using System.Data.Entity.Core.Objects; using System.Data.Entity.Infrastructure; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace SportBook.Entity { public partial class sbkEntities : DbContext { private string sysName = "SYSTEM"; public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)) { SetValuesOnBeforeSaveChanges(); return PrivateSaveChangesAsync(cancellationToken); } public override Task<int> SaveChangesAsync() { SetValuesOnBeforeSaveChanges(); return PrivateSaveChangesAsync(CancellationToken.None); } public override int SaveChanges() { SetValuesOnBeforeSaveChanges(); return PrivateSaveChangesAsync(CancellationToken.None).Result; } /// <summary> /// SaveChange之前把必要欄位寫入 /// </summary> private void SetValuesOnBeforeSaveChanges() { var trackerEntries = this.ChangeTracker.Entries() .Where(x => x.State == EntityState.Modified || x.State == EntityState.Added).ToList(); foreach (var entry in trackerEntries) { switch (entry.State) { case EntityState.Modified: entry.CurrentValues.SetValues(new { UserUpdated = sysName, DateUpdated = DateTime.UtcNow }); break; case EntityState.Added: entry.CurrentValues.SetValues(new { UserCreated = sysName, DateCreated = DateTime.UtcNow }); break; } } } /// <summary> /// SaveChange之後開始寫Log /// </summary> /// <param name="cancellationToken"></param> /// <returns></returns> private async Task<int> PrivateSaveChangesAsync(CancellationToken cancellationToken) { ObjectContext context = ((IObjectContextAdapter)this).ObjectContext; await context.SaveChangesAsync(SaveOptions.DetectChangesBeforeSave, cancellationToken).ConfigureAwait(false); var trackerEntries = this.ChangeTracker.Entries() .Where(x => x.State == EntityState.Modified || x.State == EntityState.Added).ToList(); var LogValue = new List<Entity.LogEntityValue>(); foreach (var entry in trackerEntries) { var entityName = entry.Entity.GetType().Name; //判斷entityName是否需要寫入Log var LogEntityRef = this.LogEntityRef.AsNoTracking().Where(x => x.Code == entityName).FirstOrDefault(); if (LogEntityRef != null) { //取出Table那些欄位需要更新 var LogEntityField = this.LogEntityField.AsNoTracking().Where(x => x.LogEntityRefId == LogEntityRef.Id) .Select(x => new { Id = x.Id, FieldName = x.FieldName }).ToList(); var primaryKey = entry.CurrentValues.GetValue<object>("Id"); foreach (var logfield in LogEntityField) { var originalValue = (entry.State == EntityState.Added) ? string.Empty : entry.OriginalValues.GetValue<object>(logfield.FieldName); var currentValue = entry.CurrentValues.GetValue<object>(logfield.FieldName); if (entry.State == EntityState.Modified) { if (originalValue.ToString() == currentValue.ToString()) continue; } LogValue.Add(new Entity.LogEntityValue { DateCreated = DateTime.UtcNow, UserCreated = sysName, LogEntityRefId = LogEntityRef.Id, RefObjectId = (int?)primaryKey, LogEntityFieldId = logfield.Id, OldValue = originalValue.ToString(), NewValue = currentValue.ToString() }); } } } context.AcceptAllChanges(); LogEntityValue.AddRange(LogValue); int result = await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); return result; } } }以上就是寫Log的原始碼