利用开源模块EF plus 添加系统审计功能

发布时间 2023-10-17 10:01:43作者: kkyuu

我参考的网站内容:

https://entityframework-plus.net/ef-core-audit-customization

https://entityframework-plus.net/ef-core-audit-autosave

https://csharp.hotexamples.com/examples/Z.EntityFramework.Plus/Audit/-/php-audit-class-examples.html
https://entityframework-plus.net/audit

https://stackoverflow.com/questions/58711828/how-to-use-code-first-with-entityframework-plus-audit-feature

 在构造器中加入:

        public DbSet<AuditEntry> AuditEntries { get; set; }
        public DbSet<AuditEntryProperty> AuditEntryProperties { get; set; }


        public DataContext()
        {
            AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) => AuditEntries.AddRange(audit.Entries);
        }
        public DataContext(CS cs)
             : base(cs)
        {
            AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) => AuditEntries.AddRange(audit.Entries);
        }

然后重写SaveChanges 和 SaveChangesAsync

        public override int SaveChanges()
        {  

            var audit = new Audit();
            audit.PreSaveChanges(this);
            var rowAffecteds = base.SaveChanges();
            audit.PostSaveChanges();
            var entries = audit.Entries;

            if (audit.Configuration.AutoSavePreAction != null && entries.FirstOrDefault().EntitySetName != "BaseActionLogs")
            {
                audit.Configuration.AutoSavePreAction(this, audit);
                base.SaveChanges();
            }

            return rowAffecteds;
        }

        public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            var audit = new Audit();
            audit.PreSaveChanges(this);
            var rowAffecteds = await base.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
            audit.PostSaveChanges();

            if (audit.Configuration.AutoSavePreAction != null)
            {
                audit.Configuration.AutoSavePreAction(this, audit);
                await base.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
            }

            return rowAffecteds;
        }

 

其实以上的Audit也可以用原始的方法实现:

        public override int SaveChanges()
        {
            var changes = this.ChangeTracker.Entries().Where(x => x.State == EntityState.Added ||
                                                                     x.State == EntityState.Modified ||
                                                                     x.State == EntityState.Deleted);

            foreach (var change in changes)
            {
                if (change.State == EntityState.Added)
                {
                    // Log Added
                }
                else if (change.State == EntityState.Modified)
                {
                    // Log Modified
                    var originalValues = change.OriginalValues;
                    var currentValues = change.CurrentValues;

                    foreach (var prop in change.OriginalValues.Properties)
                    {
                        var original = originalValues[prop.Name];
                        var current = currentValues[prop.Name];

                        if (!Equals(original, current))
                        {
                            // log propertyName: original --> current
                        }
                    }
                }
                else if (change.State == EntityState.Deleted)
                {
                    // log deleted
                }
            }
            return base.SaveChanges();
        }

 Database Script

https://entityframework-plus.net/ef-core-audit-autosave

CREATE TABLE [dbo].[AuditEntries] (
    [AuditEntryID] [int] NOT NULL IDENTITY,
    [EntitySetName] [nvarchar](255),
    [EntityTypeName] [nvarchar](255),
    [State] [int] NOT NULL,
    [StateName] [nvarchar](255),
    [CreatedBy] [nvarchar](255),
    [CreatedDate] [datetime] NOT NULL,
    CONSTRAINT [PK_dbo.AuditEntries] PRIMARY KEY ([AuditEntryID])
)

GO

CREATE TABLE [dbo].[AuditEntryProperties] (
    [AuditEntryPropertyID] [int] NOT NULL IDENTITY,
    [AuditEntryID] [int] NOT NULL,
    [RelationName] [nvarchar](255),
    [PropertyName] [nvarchar](255),
    [OldValue] [nvarchar](max),
    [NewValue] [nvarchar](max),
    CONSTRAINT [PK_dbo.AuditEntryProperties] PRIMARY KEY ([AuditEntryPropertyID])
)

GO

CREATE INDEX [IX_AuditEntryID] ON [dbo].[AuditEntryProperties]([AuditEntryID])

GO

ALTER TABLE [dbo].[AuditEntryProperties] 
ADD CONSTRAINT [FK_dbo.AuditEntryProperties_dbo.AuditEntries_AuditEntryID] 
FOREIGN KEY ([AuditEntryID])
REFERENCES [dbo].[AuditEntries] ([AuditEntryID])
ON DELETE CASCADE

GO