C# Audit.NET实体框架核心相关实体管理
我正在开发一个ASP.NET Core 3.1 web应用程序。我希望在数据库上持久化数据时添加审计跟踪/日志 我从中获得灵感,开始在测试项目中使用Audit.NET。C# Audit.NET实体框架核心相关实体管理,c#,entity-framework-core,audit.net,C#,Entity Framework Core,Audit.net,我正在开发一个ASP.NET Core 3.1 web应用程序。我希望在数据库上持久化数据时添加审计跟踪/日志 我从中获得灵感,开始在测试项目中使用Audit.NET。 以下是我的目标(类似于相关的SO线程): 将审核记录存储在不同的数据库中:几乎使用额外的AppAuditDbContext完成 每种类型都有一个与已审核类型匹配的审核表(带有附加审核字段):Done通过额外的AppAuditDbContext上的反射 不需要维护单独的审计实体。变化 运营数据库和审计数据库应该是无缝的:通过对额外
以下是我的目标(类似于相关的SO线程):
AppAuditDbContext
完成李>
AppAuditDbContext
上的反射李>
AppAuditDbContext
和被审计实体上的数据注释进行反射来完成
李>
但是,尽管我可以成功地删除父实体及其子实体,并获取父实体和子实体的审核数据,但我不知道如何从数据库中获取此类场景的分组审核数据。
我尝试使用Audit.NET EntityFramework的
EntityFrameworkEvent.TransactionId
和EntityFrameworkEvent.AmbientTransactionId
,但它们在DB上都是null
这是我的POCO
public interface IAuditableEntity
{
[NotMapped]
string AuditAction { get; set; }
[NotMapped]
string AuditTransactionId { get; set; }
[NotMapped]
string AuditAmbientTransactionId { get; set; }
}
public class Scope : IAuditableEntity
{
[Key]
public int Id {get;set;}
public string Name { get; set; }
public virtual ICollection<Job> Jobs { get; set; }
[NotMapped]
string AuditAction { get; set; }
[NotMapped]
string AuditTransactionId { get; set; }
[NotMapped]
string AuditAmbientTransactionId { get; set; }
}
public class Job : IAuditableEntity
{
[Key]
public int Id {get;set;}
public int ScopeId { get; set; }
public virtual Scope Scope { get; set; }
[StringLength(128)]
public string Name { get; set; }
[NotMapped]
public string AuditAction { get; set; }
[NotMapped]
public string AuditTransactionId { get; set; }
[NotMapped]
public string AuditAmbientTransactionId { get; set; }
}
公共接口IAuditableEntity
{
[未映射]
字符串审核操作{get;set;}
[未映射]
字符串AuditTransactionId{get;set;}
[未映射]
字符串AuditAmbientTransactionId{get;set;}
}
公共类作用域:IAuditableEntity
{
[关键]
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection作业{get;set;}
[未映射]
字符串审核操作{get;set;}
[未映射]
字符串AuditTransactionId{get;set;}
[未映射]
字符串AuditAmbientTransactionId{get;set;}
}
公共类作业:IAuditableEntity
{
[关键]
公共int Id{get;set;}
public int ScopeId{get;set;}
公共虚拟作用域{get;set;}
[第128段]
公共字符串名称{get;set;}
[未映射]
公共字符串审核操作{get;set;}
[未映射]
公共字符串AuditTransactionId{get;set;}
[未映射]
公共字符串AuditAmbientTransactionId{get;set;}
}
这是我的Audit.NET配置(来自Startup.cs)
公共类启动
{
public void配置服务(IServiceCollection服务)
{
services.AddDbContext
审计范围表
以下是ScopeId为5的作业的审核跟踪。
审计工作表
根据提供的数据,假设我想读取范围的删除审核(在本例中是审核范围表中的审核#9),包括其子作业的删除审核(在本例中是审核作业表中的审核#10)。我如何实现这一点
谢谢,
Matteo目前,我刚刚在实体中添加了一个自定义字段。
我在带有Guid的自定义操作中对其进行赋值
// EF AuditEventId per scope
Audit.Core.Configuration.AddCustomAction(ActionType.OnScopeCreated, scope =>
{
var id = Guid.NewGuid();
scope.SetCustomField("AuditScopeId", id);
});
这样,与同一审核事件相关的Scope
和Job
表记录将保持相同的AuditScopeId
值
[AuditDbContext(IncludeEntityObjects = true)]
public class ApplicationDbContext : AuditDbContext
{
public ApplicationDbContext([NotNullAttribute] DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Scope> Scopes { get; set; }
public DbSet<Job> Jobs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Scope>().ToTable("Scope");
modelBuilder.Entity<Job>().ToTable("Job");
}
public override int SaveChanges()
{
return base.SaveChanges();
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
return await base.SaveChangesAsync(cancellationToken);
}
}
public class ScopeController : Controller
{
private readonly ApplicationDbContext _context;
public ScopeController(ApplicationDbContext context)
{
_context = context;
}
// Other controller actions...
// POST: Scope/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var scope = await _context.Scopes.Include(s => s.Jobs).SingleOrDefaultAsync(w => w.Id == id);
// using _context.Scopes.FindAsync(id) instead does delete the children Jobs without auditing it
_context.Scopes.Remove(scope);
await _context.SaveChangesAsync().ConfigureAwait(false);
return RedirectToAction(nameof(Index));
}
}
// EF AuditEventId per scope
Audit.Core.Configuration.AddCustomAction(ActionType.OnScopeCreated, scope =>
{
var id = Guid.NewGuid();
scope.SetCustomField("AuditScopeId", id);
});