aierda 2023-03-17 08:52 采纳率: 77.2%
浏览 92
已结题

ABP怎样实现每个表的变动

需求描述:
我使用是ABP, 针对某些表的所有变动,均需要记录它的变动,包括字段名、变更
时间、记录主键、旧值、新值等。记录这些重要表的数据变动,主要是为了同步各个服务器
上的数据库,让记录保持一致。
由于时间仓促,没有时间去细研,所以在些向大家请求指点,看看有没有好的解决方案,或者
相关的代码片断,以供参考,谢谢!

  • 写回答

13条回答 默认 最新

  • dahe0825 2023-03-17 09:00
    关注

    参考GPT和自己的思路,在 ABP 框架中,你可以使用拦截器(interceptor)来实现对数据库操作的记录。具体的做法是给 DbContext 添加一个拦截器,当对表进行操作时,拦截器会触发并记录操作的详细信息。

    以下是实现步骤:

    1.创建一个类,继承自上下文拦截器 AbpDbContextInterceptor,并在该类中实现 BeforeSaveChangesAsync 和 AfterSaveChangesAsync 两个方法。这些方法将在上下文保存更改之前和之后被调用,我们需要在这些方法中记录数据变更的信息。

    public class DbLoggingInterceptor : AbpDbContextInterceptor
    {
        private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
    
        public DbLoggingInterceptor(ICurrentPrincipalAccessor currentPrincipalAccessor)
        {
            _currentPrincipalAccessor = currentPrincipalAccessor;
        }
    
        public override Task BeforeSaveChangesAsync(DbContextEventData eventData, CancellationToken cancellationToken)
        {
            foreach (var entry in eventData.Context.ChangeTracker.Entries())
            {
                if (entry.State == EntityState.Added || entry.State == EntityState.Modified || entry.State == EntityState.Deleted)
                {
                    //记录主键
                    var primaryKey = entry.Metadata.FindPrimaryKey();
                    var primaryKeyValues = primaryKey.Properties.Select(p => entry.Property(p.Name).CurrentValue.ToString()).ToList();
    
                    //记录字段名、变更时间、旧值、新值
                    var modifictionLogs = new List<ModificationLog>();
                    
                    foreach (var property in entry.Properties)
                    {
                        if (entry.State == EntityState.Modified)
                        {
                            if (property.IsModified)
                            {
                                modifictionLogs.Add(new ModificationLog
                                {
                                    ColumnName = property.Metadata.Name,
                                    OldValue = property.OriginalValue?.ToString(),
                                    NewValue = property.CurrentValue?.ToString(),
                                    ModificationTime = DateTime.UtcNow,
                                    ModifiedBy = _currentPrincipalAccessor.Principal?.Identity?.Name,
                                    PrimaryKeyValues = string.Join(",", primaryKeyValues),
                                    EntityName = entry.Metadata.Name,
                                    ChangeType = ChangeType.Modified
                                });
                            }
                        }
                        else if (entry.State == EntityState.Added)
                        {
                            modifictionLogs.Add(new ModificationLog
                            {
                                ColumnName = property.Metadata.Name,
                                NewValue = property.CurrentValue?.ToString(),
                                ModificationTime = DateTime.UtcNow,
                                ModifiedBy = _currentPrincipalAccessor.Principal?.Identity?.Name,
                                PrimaryKeyValues = string.Join(",", primaryKeyValues),
                                EntityName = entry.Metadata.Name,
                                ChangeType = ChangeType.Added
                            });
                        }
                        else if (entry.State == EntityState.Deleted)
                        {
                            modifictionLogs.Add(new ModificationLog
                            {
                                ColumnName = property.Metadata.Name,
                                OldValue = property.OriginalValue?.ToString(),
                                ModificationTime = DateTime.UtcNow,
                                ModifiedBy = _currentPrincipalAccessor.Principal?.Identity?.Name,
                                PrimaryKeyValues = string.Join(",", primaryKeyValues),
                                EntityName = entry.Metadata.Name,
                                ChangeType = ChangeType.Deleted
                            });
                        }
                    }
    
                    //通过事件通知进行记录修改信息
                    eventData.Context.GetService<IEventBus>().Publish(new EntityModificationEventData<ModificationLog>(modifictionLogs));
                }
            }
    
            return Task.CompletedTask;
        }
    
        public override Task AfterSaveChangesAsync(DbContextEventData eventData, CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
    }
    

    在上述代码中,我们使用了一个 ModificationLog 类型来记录数据库中数据的变动信息:

    public class ModificationLog : Entity<Guid>
    {
        public string EntityName { get; set; }
    
        public string ColumnName { get; set; }
    
        public string PrimaryKeyValues { get; set; }
    
        public string OldValue { get; set; }
    
        public string NewValue { get; set; }
    
        public ChangeType ChangeType { get; set; }
    
        public DateTime ModificationTime { get; set; }
    
        public string ModifiedBy { get; set; }
    }
    
    public enum ChangeType
    {
        Added,
        Modified,
        Deleted
    }
    

    2.注册拦截器
    在 ABP 框架中,你可以在应用启动时进行拦截器的注册。在 YourProjectNameEntityFrameworkCoreModule 类中使用 ConfigureServices 方法注册该拦截器:

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddAbpDbContext<MyProjectNameDbContext>(options =>
        {
            //exsiting code
    
            options.AddInterceptors(new DbLoggingInterceptor(context.Services.GetRequiredService<ICurrentPrincipalAccessor>()));
        });
    }
    

    在上述代码中,我们将 DbLoggingInterceptor 添加到了 MyProjectNameDbContext 上下文中。

    3.订阅事件
    在上述代码中,我们使用了一个 EntityModificationEventData 事件,它会在数据变动时被发布。订阅该事件,即可对数据变动进行处理。

    public class ModificationLogAppService : ApplicationService
    {
        private readonly IRepository<ModificationLog, Guid> _modificationLogRepository;
    
        public ModificationLogAppService(IRepository<ModificationLog, Guid> modificationLogRepository)
        {
            _modificationLogRepository = modificationLogRepository;
        }
    
        public Task HandleEntityModificationEventAsync(EntityModificationEventData<ModificationLog> eventData)
        {
            var modificationLogs = eventData.Entities.ToList();
    
            foreach (var modificationLog in modificationLogs)
            {
                _modificationLogRepository.InsertAsync(modificationLog);
            }
    
            return Task.CompletedTask;
        }
    }
    
    
    

    在上述代码中,我们创建了一个应用服务 ModificationLogAppService,它注册了 EntityModificationEventData 事件,并在处理事件时将数据变动信息保存到数据库中。你需要在 YourProjectNameApplicationModule.cs 类中引入该服务,以便在应用启动时能够自动订阅该事件。

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        Configure<AbpBackgroundJobOptions>(options =>
        {
            options.IsJobExecutionEnabled = false;
        });
        
        context.Services.AddAbpDbContext<MyProjectNameDbContext>(options =>
        {
            // existing code
    
            options.AddInterceptors(new DbLoggingInterceptor(context.Services.GetRequiredService<ICurrentPrincipalAccessor>()));
        });
    
        Configure<AbpDistributedEventBusOptions>(options =>
        {
            options.GlobalHandlers.Add<ModificationLogAppService>();
        });
    }
    
    
    

    在上述代码中,我们通过 Configure 方法启用了事件总线,并注册了 ModificationLogAppService,以处理 EntityModificationEventData 事件。

    至此,我们已经实现了 ABP xNext 框架下对于某些表的数据变动的记录。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(12条)

报告相同问题?

问题事件

  • 系统已结题 3月29日
  • 已采纳回答 3月21日
  • 修改了问题 3月17日
  • 创建了问题 3月17日

悬赏问题

  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题
  • ¥15 qgcomp混合物线性模型分析的代码出现错误:Model aliasing occurred
  • ¥100 已有python代码,要求做成可执行程序,程序设计内容不多
  • ¥15 目标检测项目无法读取视频
  • ¥15 GEO datasets中基因芯片数据仅仅提供了normalized signal如何进行差异分析
  • ¥15 小红薯封设备能解决的来
  • ¥100 求采集电商背景音乐的方法
  • ¥15 数学建模竞赛求指导帮助
  • ¥15 STM32控制MAX7219问题求解答