.NET实现字段变更记录

简介

有时候在开发中,需要对实体的某个字段做变更日志,如果显式保存日志,会对业务代码耦合太大。
本文采用重写DbContext的SaveChanges方法实现,在指定字段变更时,自动添加变更日志,减少对业务代码的耦合。

实体定义

ToDoItem是主实体,ToDoItemTextLog是ToDoItem的Text字段的变更记录

    public class ToDoItem : FullAuditedEntity<long>
    {
        public string Text { get; set; }
    }

    public class ToDoItemTextLog : FullAuditedEntity<long>
    {
        public long ToDoItemId { get; set; }
        [ForeignKey(nameof(ToDoItemId))]
        public ToDoItem ToDoItem { get; set; }

        public string NewValue { get; set; }//新值
        public string OriginalValue { get; set; }//旧值
    }

在项目的DbContext类中,增加一个方法

        protected virtual ICollection<ToDoItemTextLog> ChangeToDoItemTextLog()
        {
            //获取跟踪的实体
            var entries = ChangeTracker.Entries().ToList();
            //定义数组
            var logs = new List<ToDoItemTextLog>();

            foreach (var entry in entries)
            {
                //如果该实体是ToDoItem,并且是被修改的状态
                if (entry.Entity is ToDoItem toDoItem && entry.State == EntityState.Modified)
                {
                    //获取Text字段的新旧值,并存入数组
                    //var properties = entry.Metadata.GetProperties();
                    var propEntry = entry.Property("Text");
                    logs.Add(new ToDoItemTextLog()
                    {
                        ToDoItemId = toDoItem.Id,
                        NewValue = propEntry.CurrentValue.ToString(),
                        OriginalValue = propEntry.OriginalValue.ToString(),
                    });
                }
            }
            return logs;
        }

重写DbContext的SaveChanges和SaveChangesAsync

保存变更记录数组的代码需要放在base.SaveChanges()之前

        public override int SaveChanges(bool acceptAllChangesOnSuccess)
        {
            // ……其他本文无关代码

            // 获取变更记录的数组
            var toDoItemTextLogs = ChangeToDoItemTextLog();
            if (toDoItemTextLogs.Count > 0)
                // 开启事务
                using (var tran = Database.BeginTransaction())
                {
                    // 将该数组存入数据库
                    AddRange(toDoItemTextLogs);
                    tran.Commit();
                }

            // ……其他本文无关代码
        }

        public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
        {
            // ……其他本文无关代码

            var toDoItemTextLogs = ChangeToDoItemTextLog();
            if (toDoItemTextLogs.Count > 0)
                using (var tran = await Database.BeginTransactionAsync(cancellationToken))
                {
                    AddRange(toDoItemTextLogs);
                    await tran.CommitAsync(cancellationToken);
                }

            // ……其他本文无关代码
        }
posted @ 2023-02-03 09:23  cnblogsName  阅读(190)  评论(0编辑  收藏  举报