本文介绍了如何使用Audit.Net定位另一个数据库-Audit.EntityFramework.Core的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过Audit.EntityFramework.Core 包 tree / master / src / Audit.EntityFramework rel = nofollow noreferrer> Audit.Net存储库,但遇到了一些困难。我无法保存更改或定位到其他数据库。我已经修改了 SaveChanges SaveChangesAsync 函数以调用 Audit.Net DbContextHelper 类的保存功能,但是我缺少了一些东西。

I'm trying to implement the Audit.EntityFramework.Core package from the Audit.Net repository but am running into some difficulty. I'm unable to save changes or target a different database. I've modified my SaveChanges and SaveChangesAsync function to call the Audit.Net DbContextHelper class's save functions but I'm missing something.

有没有一种方法可以


  1. 使用继承的审计 DbContext 定位另一个数据库来存储审计数据从 DbContext 我要审核吗?

  1. Target another database for storing audit data using an audit DbContext that inherits from the DbContext I'm trying to audit?
public class MyDbContext : DbContext {} //Types defined here
public class AuditDbContext : MyDbContext {} //This context stores audit data into a different DB


  • 在建立全局连接时是否不需要在类型及其审核类型之间进行映射? (我试图避免针对当前类型发生重大变化的模型为每种类型显式调用 AuditTypeMapper )。

  • Not require mapping between the type and its audited type when setting up a global connection? (I'm trying to avoid calling AuditTypeMapper explicitly for each type with a model that's currently undergoing a lot of change).

    //MyDbContext has different connection string than AuditDbContext
    Audit.Core.Configuration.Setup()
    .UseEntityFramework(x => x
        .UseDbContext<AuditDbContext>());
    


  • 我尝试了类似于以下代码但是在 SaveChanges 上出现运行时错误,表明未设置模型。为 AuditDbContext 添加迁移没有帮助。

    I've tried code that resembles the following but get runtime errors on SaveChanges that indicate that there is no model set up. Adding a migration for the AuditDbContext didn't help.

    推荐答案

    我弄清楚了我要做什么。



    我的设计目标是:



    I figured out what I was trying to do.

    My design goals were:


    1. 将审核记录存储在另一个数据库中

    2. 每个审核表都有一个审核表与已审核类型匹配的类型(带有其他审核字段)

    3. 不需要维护单独的审核实体。业务数据库和审计数据库之间的更改应该是无缝的



    我发现无效的是:



    Things I discovered that did not work were:


    1. 创建从我的可操作DbContext继承的审计DbContext无法正常工作,因为在审计数据库中不能以相同的方式处理关系,DBSet和ID。

    2. 使用TypeBuilder对操作类型进行反射来动态创建类型是行不通的,因为Audit.Net在操作类型和审计类型之间强制转换对象,并且无法将CLR类型转换为动态创建的类型。

    3. 混合具体类型和EF Core阴影类型无效。



    已采取的步骤



    Steps Taken


    1. 设置全局审核(在主要设置代码中)

    1. Set up Global Auditing (in main setup code)

    //Global setup of Auditing
    var auditDbCtxOptions = new DbContextOptionsBuilder<MyAuditDbContext>()
        .UseSqlServer(options.AuditDbConnectionString)
        .Options;
    
    Audit.Core.Configuration.Setup()
        .UseEntityFramework(x => x
            .UseDbContext<MyAuditDbContext>(auditDbCtxOptions)
            .AuditTypeNameMapper(typeName => 
            {
                return typeName;
            })
            .AuditEntityAction<AuditInfo>((ev, ent, auditEntity) =>
            {
                auditEntity.DatabaseAction = ent.Action;
            }));
    


  • 我的审核模型继承自基本类 AuditInfo

    public abstract class AuditInfo
    {
        public DateTime Created { get; set; }
        public DateTime? Updated { get; set; }
        public string CreatedBy { get; set; }
        public string UpdatedBy { get; set; }
    
        [NotMapped] //This is not mapped on the operational DB
        public string DatabaseAction { get; set; }
    }
    


  • 使用新的<$创建基于反射的审核架构c $ c> DbContext 和 OnModelCreating

    public class MyAuditContext : DbContext
    {
        public MyAuditContext(DbContextOptions<MyAuditContext> options) : base(options)
        {
    
        }
    
        private readonly Type[] AllowedTypes = new Type[] 
        { 
            typeof(bool),
            typeof(int),
            typeof(decimal),
            typeof(string),
            typeof(DateTime),
        };
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            Console.WriteLine($"Generating dynamic audit model");
    
            //Go through each of the types in Hsa.Engine.Data.Models
            var asm = Assembly.GetExecutingAssembly();
            var modelTypes = asm.GetTypes()
                .Where(type => type.Namespace == "My.Data.Models.Namespace");
    
            //Create an entity For each type get all the properties on the model
            foreach(var model in modelTypes.Where(t => t.IsClass && !t.IsAbstract && t.BaseType == typeof(AuditInfo)))
            {
                Console.WriteLine($"Creating entity for {model.Name}");
    
                var table = modelBuilder.Entity(model, entity => 
                {
                    //Remove all types from base model, otherwise we get a bunch of noise about foreign keys, etc.
                    foreach(var prop in model.GetProperties())
                    {
                        entity.Ignore(prop.Name);
                    }
    
                    foreach(var prop in model.GetProperties().Where(p => AllowedTypes.Any(t => p.PropertyType.IsAssignableFrom(t))))
                    {
                        Console.WriteLine($"   Adding field: {prop.Name} - Type: {prop.PropertyType.Name}");
                        //Create a typed field for each property, not including ID or foreign key annotations (do include field lengths)
    
                        var dbField = entity.Property(prop.PropertyType, prop.Name);
    
                        if(prop.PropertyType.IsEnum)
                        {
                            dbField.HasConversion<string>();
                        }
    
                        if(dbField.Metadata.IsPrimaryKey())
                        {
                            dbField.ValueGeneratedNever(); //Removes existing model primary keys for the audit DB
                        }
                    }
    
                    //Add audit properties
                    entity.Property<int>("AuditId").IsRequired().UseSqlServerIdentityColumn();
                    entity.Property<DateTime>("AuditDate").HasDefaultValueSql("getdate()");
                    entity.Property<string>("DatabaseAction"); //included on AuditInfo but NotMapped to avoid putting it on the main DB. Added here to ensure it makes it into the audit DB
    
                    entity.HasKey("AuditId");
                    entity.HasIndex("Id");
                    entity.ToTable("Audit_" + model.Name);
                });
            }
    
            base.OnModelCreating(modelBuilder);
        }
    }
    
    


  • 为主要数据库和审计数据库。

  • 有些人可能不需要达到这些级别,但是我想分享一下,以防有人需要类似的东西使用Audit.Net

    Some people may not need to go to these levels but I wanted to share in case anyone needed something similar when using Audit.Net

    这篇关于如何使用Audit.Net定位另一个数据库-Audit.EntityFramework.Core的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

    10-22 15:53