第一篇 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 库里面,他有提供,等一下我会实作一下给大家看一下,这个库所提供的功能,如下
- Batch Operations
- LINQ
- Query
- Audit
如果购买了 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(); this.Property(m => m.OrderCreator)
.IsRequired()
.HasMaxLength(); this.Property(m => m.OrderStatus)
.IsRequired()
.HasMaxLength(); this.Property(m => m.Description)
.HasMaxLength(); this.Property(m => m.Creator)
.IsRequired()
.HasMaxLength(); this.Property(m => m.LastModifier)
.HasMaxLength()
.HasMaxLength(); 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](),
[EntityTypeName] [nvarchar](),
[State] [int] NOT NULL,
[StateName] [nvarchar](),
[CreatedBy] [nvarchar](),
[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](),
[PropertyName] [nvarchar](),
[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
第一篇 Entity Framework Plus 之 Audit的更多相关文章
- 第三篇 Entity Framework Plus 之 Query Cache
离上一篇博客,快一周,工作太忙,只能利用休息日来写一些跟大家分享,Entity Framework Plus 组件系列文章,之前已经写过两篇 第一篇 Entity Framework Plus 之 A ...
- 第二篇 Entity Framework Plus 之 Query Future
从性能的角度出发,能够减少 增,删,改,查,跟数据库打交道次数,肯定是对性能会有所提升的(这里单纯是数据库部分). 今天主要怎样减少Entity Framework查询跟数据库打交道的次数,来提高查询 ...
- 第四篇 Entity Framework Plus 之 Batch Operations
用 Entity Framework 进行 增,删,改.都是基于Model进行的,且Model都是有状态追踪的.这样Entity Framework才能正常增,删,改. 有时候,要根据某个字段,批量 ...
- .NET基础篇——Entity Framework 数据转换层通用类
在实现基础的三层开发的时候,大家时常会在数据层对每个实体进行CRUD的操作,其中存在相当多的重复代码.为了减少重复代码的出现,通常都会定义一个共用类,实现相似的操作,下面为大家介绍一下Entity F ...
- Entity Framework Plus 系列目录
Entity Framework Plus 系列文章计划的已经全部写完,可能还有其他功能没有写到,希望大家能够多动手,尝试一下使用,一定会给您带来一些帮助的.文章全部写完,也应该出一个目录方便查看,目 ...
- Entity Framework 6.1-Code First【转】
Entity Framework 6.1-Code First 分类: Entity Framework 2014-04-21 14:56 2034人阅读 评论(0) 收藏 举报 entityen ...
- Entity Framework 6.0 入门系列 第一篇
Entity Framework 6.0 入门系列 第一篇 好几年前接触过一些ef感觉不是很好用,废弃.但是 Entity Framework 6.0是经过几个版本优化过的产物,性能和功能不断完善,开 ...
- 第一篇:Entity Framework 简介
先从ORM说起吧,很多年前,由于.NET的开源组件不像现在这样发达,更别说一个开源的ORM框架,出于项目需要,以及当时OOP兴起(总不至于,在项目里面全是SQL语句),就自己开始写ORM框架.要开发O ...
- 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述
微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...
随机推荐
- node.js学习(二)--Node.js控制台(REPL)&&Node.js的基础和语法
1.1.2 Node.js控制台(REPL) Node.js也有自己的虚拟的运行环境:REPL. 我们可以使用它来执行任何的Node.js或者javascript代码.还可以引入模块和使用文件系统. ...
- 一起学 Java(二)面向对象
一.方法函数 函数也称为方法,就是定义在类中的具有特定功能的一段独立代码.用于定义功能,提高代码的复用性. 函数的特点1> 定义函数可以将功能代码进行封装,便于对该功能进行复用:2> 函数 ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- 数塔问题(DP算法)自底向上计算最大值
Input 输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数 ...
- Jenkins的一个bug-同时build一个项目两次导致失败
我们有一个job A, A只是配置了一些参数,它会去触发模板job B. 我一开始点击构建A, 马上发现参数配置不对,于是撤消了构建,但是我没有发现B已经被触发,我重新配置参数,然后再次构建A,这个时 ...
- hibernate5.2需要的最少jar文件
hibernate5.2需要的最少jar文件: required文件夹中的所有jar文件 + mysql-connector-java-bin.jar.
- Unity C#最佳实践(上)
本文为<effective c#>的读书笔记,此书类似于大名鼎鼎的<effective c++>,是入门后提高水平的进阶读物,此书提出了50个改进c#代码的原则,但是由于主要针 ...
- TCP三次握手图解
- JS中给正则表达式加变量
前不久同事询问我js里面怎么给正则中添加变量的问题,遂写篇博客记录下. 一.字面量 其实当我们定义一个字符串,一个数组,一个对象等等的时候,我们习惯用字面量来定义,例如: var s = &quo ...
- DIP原则、IoC以及DI
一.DIP原则 高层模块不应该依赖于底层模块,二者都应该依赖于抽象. 抽象不应该依赖于细节,细节应该依赖于抽象. 该原则理解起来稍微有点抽象,我们可以将该原则通俗的理解为:"依赖于抽象&qu ...