需求描述:
我使用是ABP, 针对某些表的所有变动,均需要记录它的变动,包括字段名、变更
时间、记录主键、旧值、新值等。记录这些重要表的数据变动,主要是为了同步各个服务器
上的数据库,让记录保持一致。
由于时间仓促,没有时间去细研,所以在些向大家请求指点,看看有没有好的解决方案,或者
相关的代码片断,以供参考,谢谢!
ABP怎样实现每个表的变动
- 写回答
- 好问题 0 提建议
- 追加酬金
- 关注问题
- 邀请回答
-
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 框架下对于某些表的数据变动的记录。
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报
悬赏问题
- ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
- ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
- ¥15 手机接入宽带网线,如何释放宽带全部速度
- ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
- ¥15 ETLCloud 处理json多层级问题
- ¥15 matlab中使用gurobi时报错
- ¥15 这个主板怎么能扩出一两个sata口
- ¥15 不是,这到底错哪儿了😭
- ¥15 2020长安杯与连接网探
- ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么