第一篇 Entity Framework Plus 之 Audit

一般系统会有登陆日志,操作日志,异常日志,已经满足大部分的需求了。但是有时候,还是需要Audit 审计日志,审计日志,主要针对数据增,改,删操作数据变化的记录,主要是对数据变化的一个追踪过程。其中主要追踪数据关键点如下

1. 新增 具体新增哪些数据,值是什么,新增人谁。

2. 修改 具体修改哪些数据,之前值是什么,修改后值是什么,修改人谁。

3. 删除 具体删除哪些数据,之前值是什么,删除人谁。

有了这个Audit追踪过程,当那天,用户操作的数据出现问题,你就可以根据这个Audit将数据恢复到某个状态,当然这个Audit,也不仅仅数据出问题才有用,在分析数据时,也有用。

这几年都在做基于ASP.NET MVC & Entity Framework 搭建企业技术框架,很早之前就想自己写一个Audit机制,想着把数据变化保存为json,由于之前公司很多事情所有也没有静下心来想怎么在现有架构上加这块的事情。这几天自己也在找工作(深圳找工作,如果大家的公司缺一个架构的岗位,我可以客串一下,13926537904,不胜感激),所有不忙了,就再次想起Audit来。就开始倒腾起来。

ZZZ Project 这家外国公司,有很多关于.NET和数据访问的项目,有收费的,有开源的,我之前介绍过 Z.ExtensionMethods 一个强大的开源扩展库 就出自该名下,其他有 如下

1. Bulk-Operations ,这个我相信大家也不陌生,Ado.Net 批量操作数据组件 收费

2. EntityFramework-Extensions ,这个Entity Framework 扩展库,这个是EntityFramework 批量操作数据扩展组件 收费

3. EntityFramework-Plus 这个是最近才发布的 Entity Framework + 库,比EntityFramework-Extensions 新增更多的功能。开源免费

4. Dapper-Plus 这个是最近才发布的 Drpper + 库

5. Eval-SQL.NET 关于SQL的,没有使用过,暂时不详细说。

6. Eval-Expression.NET 关于表达式的,没有使用过,暂时不详细说。

等等,还一些我就不一一介绍了,大家可以在下面网站,细看自己感兴趣的。

zzz projects GitHub: https://github.com/zzzprojects

我要说的Audit,在  EntityFramework-Plus 库里面,他有提供,等一下我会实作一下给大家看一下,这个库所提供的功能,如下

如果购买了 EntityFramework-Extensions 这个扩展库,EntityFramework-Extensions 这个库的功能也会包含在里面。

EntityFramework-Plus GitHub 主页 : http://entityframework-plus.net/

EntityFramework-Plus GitHub 源代码: https://github.com/zzzprojects/EntityFramework-Plus

说了一大堆废话,没有入正题,不好意思,开始真正实作 EntityFramework-Plus 之 Audit 部分。

一.  创建解决方案,以及新增基础设施项目(DbContext,Models,Mapping,Demo),这里就不再介绍了,大家参考 Entity Framework 6 开发系列 目录 实作一下即可,就只贴一些关键代码以及项目截图(还未引用EntityFramework-Plus)。

1. 解决方案截图

EntityFrameworkPlus.Demo 项目:控制台程序,应用层 Demo。

EntityFrameworkPlus.DbContext 项目 :DbContext

EntityFrameworkPlus.Mappings 项目:映射模型

EntityFrameworkPlus.Models 项目:模型

2. 关键代码 (还是以订单为义务)

OrderModel

using System;

namespace EntityFrameworkPlus.Models
{
    public class OrderModel
    {
        public Guid OrderGuid { get; set; }
        public string OrderNo { get; set; }
        public string OrderCreator { get; set; }
        public DateTime OrderDateTime { get; set; }
        public string OrderStatus { get; set; }
        public string Description { get; set; }
        public string Creator { get; set; }
        public DateTime CreateDateTime { get; set; }
        public string LastModifier { get; set; }
        public DateTime? LastModifiedDateTime { get; set; }
    }
}

OrderMapp

using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFrameworkPlus.Models;

namespace EntityFrameworkPlus.Mappings
{
    public class OrderMap : EntityTypeConfiguration<OrderModel>
    {
        public OrderMap()
        {
            this.HasKey(m => m.OrderGuid);

            this.Property(m => m.OrderGuid)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            this.Property(m => m.OrderNo)
                .IsRequired()
                .HasMaxLength(30);

            this.Property(m => m.OrderCreator)
                .IsRequired()
                .HasMaxLength(20);

            this.Property(m => m.OrderStatus)
                .IsRequired()
                .HasMaxLength(30);

            this.Property(m => m.Description)
                .HasMaxLength(1000);

            this.Property(m => m.Creator)
                .IsRequired()
                .HasMaxLength(20);

            this.Property(m => m.LastModifier)
             .HasMaxLength(15)
             .HasMaxLength(20);

            this.ToTable("Sample_Order");

            this.Property(m => m.OrderGuid).HasColumnName("OrderGuid");
            this.Property(m => m.OrderNo).HasColumnName("OrderNo");
            this.Property(m => m.OrderCreator).HasColumnName("OrderCreator");
            this.Property(m => m.OrderDateTime).HasColumnName("OrderDateTime");
            this.Property(m => m.OrderStatus).HasColumnName("OrderStatus");
            this.Property(m => m.Description).HasColumnName("Description");
            this.Property(m => m.Creator).HasColumnName("Creator");
            this.Property(m => m.CreateDateTime).HasColumnName("CreateDateTime");
            this.Property(m => m.LastModifier).HasColumnName("LastModifier");
            this.Property(m => m.LastModifiedDateTime).HasColumnName("LastModifiedDateTime");
        }
    }
}

EntityFrameworkPlusDbContext

using System.Data.Entity;
using EntityFrameworkPlus.Mappings;
using EntityFrameworkPlus.Models;

namespace EntityFrameworkPlus.DbContext
{
    public class EntityFrameworkPlusDbContext : System.Data.Entity.DbContext
    {
        public EntityFrameworkPlusDbContext()
            : base("EntityFrameworkPlusConnection")
        {
        }
        public DbSet<OrderModel> Orders { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {

            modelBuilder.Configurations.Add(new OrderMap());

            base.OnModelCreating(modelBuilder);
        }

    }
}

Program

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EntityFrameworkPlus.DbContext;
using EntityFrameworkPlus.Models;

namespace EntityFrameworkPlus.Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            AddOrder();
        }
        public static void AddOrder()
        {
            using (var dbContext = new EntityFrameworkPlusDbContext())
            {
                dbContext.Orders.Add(new OrderModel
                {
                    OrderNo = "ORDER0001",
                    OrderCreator = "david",
                    OrderDateTime = DateTime.Now,
                    OrderStatus = "已出库",
                    Creator = "david",
                    CreateDateTime = DateTime.Now
                });
                dbContext.SaveChanges();
            }
        }
    }
}

3. 项目与项目引用关系(代码图)

二. EntityFramework-Plus 使用

1. 在EntityFrameworkPlus.DbContext,EntityFrameworkPlus.Demo 两个项目中安装 EntityFramework-Plus 库,右键项目 选择“管理NuGet程序包”,联机中,搜索“Z.EntityFramework.Plus”(搜到很多个EntityFramework.Plus 开头组件,大家不要被吓到了,zzz projects 将 Z.EntityFramework.Plus 组件,按照EntityFramework版本分,然后再按照 Z.EntityFramework.Plus 功能来分,比较独立,所以会有这么多个组件,我们这里用的是Entity Framework 6 ,要用到Audit功能),选择 “EntityFramework.Plus (EF6) Audit” 进行安装。

2. EntityFramework.Plus Audit 把数据追踪记录,分成两个表记录

AuditEntries 表 ,记录实体 名称,所属上一级命名空间,状态(增,改,删),状态名称,创建人。

AuditEntryProperties  表,具体数据字段信息,字段名称,关系名称,记录旧,新值。

将 EntityFramework.Plus 提供创建两个表的SQL语句,在自己的数据库里面执行。我的数据库“EntityFrameworkSample”,执行完了,总共就有三个“AuditEntries”,“AuditEntryProperties ”,“Sample_Order”。下面是创建 Audit 相关表SQL,以及数据库结构截图。

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

3. 在 “EntityFrameworkPlus.DbContext” 项目的“EntityFrameworkPlusDbContext” ,配置Audit 两个表实体集合。配置完成代码如下。

using System.Data.Entity;
using EntityFrameworkPlus.Mappings;
using EntityFrameworkPlus.Models;
using Z.EntityFramework.Plus;

namespace EntityFrameworkPlus.DbContext
{
    public class EntityFrameworkPlusDbContext : System.Data.Entity.DbContext
    {
        public EntityFrameworkPlusDbContext()
            : base("EntityFrameworkPlusConnection")
        {
        }
        public DbSet<AuditEntry> AuditEntries { get; set; }
        public DbSet<AuditEntryProperty> AuditEntryProperties { get; set; }
        public DbSet<OrderModel> Orders { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {

            modelBuilder.Configurations.Add(new OrderMap());

            base.OnModelCreating(modelBuilder);
        }

    }
}

4. 在“EntityFrameworkPlus.Demo” Program 调整代码,使用EntityFramework.Plus Audit 代码,以及增加及调整了 对Sample_Order  增,改,删数据操作。调整代码如下。

using System;
using System.Data.Entity;
using System.Linq;
using EntityFrameworkPlus.DbContext;
using EntityFrameworkPlus.Models;
using Z.EntityFramework.Plus;

namespace EntityFrameworkPlus.Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            AuditManager.DefaultConfiguration.AutoSavePreAction = (context, audit) =>
            {
                var customAuditEntries = audit.Entries.Select(x => Import(x));
                (context as EntityFrameworkPlusDbContext).AuditEntries.AddRange(customAuditEntries);
            };

            AddOrder();
        }
        public static void AddOrder()
        {
            using (var dbContext = new EntityFrameworkPlusDbContext())
            {
                var audit = new Audit { CreatedBy = "david" };
                dbContext.Orders.Add(new OrderModel
                {
                    OrderNo = "ORDER0001",
                    OrderCreator = "david",
                    OrderDateTime = DateTime.Now,
                    OrderStatus = "已出库",
                    Creator = "david",
                    CreateDateTime = DateTime.Now
                });
                dbContext.SaveChanges(audit);
            }
        }
        public static void UpdateOrder()
        {
            using (var dbContext = new EntityFrameworkPlusDbContext())
            {
                var audit = new Audit { CreatedBy = "david" };
                var orderAsync = dbContext.Orders.FirstAsync();
                var order = orderAsync.Result;
                order.LastModifier = "davidzhou";
                order.LastModifiedDateTime = DateTime.Now;
                order.OrderStatus = "已完成";
                dbContext.Entry(order);
                dbContext.SaveChanges(audit);
            }
        }
        public static void DeleteOrder()
        {
            using (var dbContext = new EntityFrameworkPlusDbContext())
            {
                var audit = new Audit { CreatedBy = "david" };
                var orderAsync = dbContext.Orders.FirstAsync();
                var order = orderAsync.Result;
                dbContext.Entry(order).State = EntityState.Deleted;
                dbContext.SaveChanges(audit);
            }
        }

        public static AuditEntry Import(AuditEntry entry)
        {
            var customAuditEntry = new AuditEntry
            {
                EntitySetName = entry.EntitySetName,
                EntityTypeName = entry.EntityTypeName,
                State = entry.State,
                StateName = entry.StateName,
                CreatedBy = entry.CreatedBy,
                CreatedDate = entry.CreatedDate
            };
            customAuditEntry.Properties = entry.Properties.Select(x => Import(x)).ToList();

            return customAuditEntry;
        }
        public static AuditEntryProperty Import(AuditEntryProperty property)
        {
            var customAuditEntry = new AuditEntryProperty
            {
                RelationName = property.RelationName,
                PropertyName = property.PropertyName,
                OldValue = property.OldValueFormatted,
                NewValue = property.NewValueFormatted
            };
            return customAuditEntry;
        }
    }
}

5. 对 Sample_Order 表,做新增 操作,三张表变化如图,我这边就不解释了,大家应该多看得懂。

5. 对 Sample_Order 表,做修改 操作,三张表变化如图,我这边就不解释了,大家应该多看得懂。

5. 对 Sample_Order 表,做删除 操作,三张表变化如图,我这边就不解释了,大家应该多看得懂。

好了,到此博文,已经结束,这里要说明的,Entity Framework Plus Audit 部分,我只使用到一些,还要其他大家可以自行,GitHub 更加深入的了解。

此篇博文的源代码: https://github.com/haibozhou1011/EntityFramework-PlusSample

时间: 2024-08-07 00:16:46

第一篇 Entity Framework Plus 之 Audit的相关文章

第二篇 Entity Framework Plus 之 Query Future

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 从性能的角度出发,能够减少 增,删,改,查,跟数据库打交道次数,肯定是对性能会有所提升的(这里单纯是数据库部分). 今天主要怎样减少Entity Framework查询跟数据库打交道的次数,来提高查询性能. 举一个大家最常用功能 "分页&quo

.NET基础篇——Entity Framework 数据转换层通用类

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 在实现基础的三层开发的时候,大家时常会在数据层对每个实体进行CRUD的操作,其中存在相当多的重复代码.为了减少重复代码的出现,通常都会定义一个共用类,实现相似的操作,下面为大家介绍一下Entity Framework时常用到的通用类.首先在数据

Entity Framework Plus 系列目录

Entity Framework Plus 系列文章计划的已经全部写完,可能还有其他功能没有写到,希望大家能够多动手,尝试一下使用,一定会给您带来一些帮助的.文章全部写完,也应该出一个目录方便查看,目录如下 第一篇 Entity Framework Plus 之 Audit 第二篇 Entity Framework Plus 之 Query Future 第三篇 Entity Framework Plus 之 Query Cache 第四篇 Entity Framework Plus 之 Bat

Entity Framework 6.1-Code First【转】

Entity Framework 6.1-Code First 分类: Entity Framework 2014-04-21 14:56 2034人阅读 评论(0) 收藏 举报 entityentity framework框架 Code First-代码优先,先创建好领域模型.新建MyDbContext继承DbContext.根据代码自动生成数据库 Code First优点 1.可以自由的创建领域模型,基本不受EF框架的限制.自由的命名.程序员只需要关心对象间的关系.基本做到了与数据库的完全分

Entity Framework 4 第一篇 POCO

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 Entity Framework 4 第一篇 POCO 在EFv1版本中,并没有提供对POCO(Plain Old CLR Objects)的支持.目前,在.Net4.0 Beta2中的EF 4完善了很多.可以预见,正式的EF4版本应该会有很多

第一篇:Entity Framework 简介

先从ORM说起吧,很多年前,由于.NET的开源组件不像现在这样发达,更别说一个开源的ORM框架,出于项目需要,以及当时OOP兴起(总不至于,在项目里面全是SQL语句),就自己开始写ORM框架.要开发ORM框架首先要了解ORM概念. ORM 对象关系映射,O(Object) 对象,在项目中就是实体,更加精确的来说就是数据Model,也可以说持久化类.R(Relation) 关系数据,M (Mapping)映射,将对象映射到关系数据,将关系数据映射到对象的过程. 更加直观理解就是,ORM 就是以OO

《Entity Framework 6 Recipes》中文翻译系列 目录篇 -持续更新

为了方便大家的阅读和学习,也是响应网友的建议,在这里为这个系列做一个目录.在目录开始这前,我先来回答之前遇到的几个问题. 1.为什么要学习EF? 这个问题很简单,项目需要.这不像学校,没人强迫你学习! 我学习EF的原因主要是: a.EF是微软推荐的数据库访问技术: b.能提高我的开发效率,我不喜欢写那密密麻麻的SQL: c.比我写的SQL更合理,更快.目前EF生成的SQL的质量已经很高了.你比较熟悉SQL的话,那它在速度上肯定比不上你,新手的话就别跟我争快慢了,能写一像样的SQL就不错了.至少我

第二篇:Entity Framework CodeFirst &amp; Model 映射

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 前一篇 第一篇:Entity Framework 简介 我有讲到,ORM 最关键的 Mapping,也提到了最早实现Mapping的技术,就是 特性 + 反射,那Entity Framework 实现Mapping 又是怎样的呢? Entity

Entity Framework学习中级篇

1-EF支持复杂类型的实现 本节,将介绍如何手动构造复杂类型(ComplexType)以及复杂类型的简单操作. 通常,复杂类型是指那些由几个简单的类型组合而成的类型.比如:一张Customer表,其中有FristName和LastName字段,那么对应的Customer实体类将会有FristName和LastName这两个属性.当我们想把FirstName和LastName合成一个名为CustomerName属性时,此时,如果要在EF中实现这个目的,那么我们就需要用到复杂类型. 目前,由于EF不