第一篇 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

    • Batch Delete

    • Batch Update

  • LINQ

    • LINQ Dynamic

  • Query

    • Query Cache

    • Query Deferred

    • Query Filter

    • Query Future

    • Query IncludeFilter

    • Query IncludeOptimized

  • 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

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


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,以及数据库结构截图。 

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


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  增,改,删数据操作。调整代码如下。


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

原文地址:http://www.cnblogs.com/davidzhou/p/5376542.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329686.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

本想试试看,结果却拿到了京东的Offer

转载自 本想试试看&#xff0c;结果却拿到了京东的Offer 最近&#xff0c;春招已经基本接近尾声了&#xff0c;我找了几位拿到名企Offer的粉丝&#xff0c;请他们总结了面试经验&#xff0c;近期会分批的推送给大家。希望给那些正在准备秋招的同学提供些帮助。 今天给大家分享的…

ping 命令使用代理_网络检测知识篇:ping命令使用知识,你知道几点?

Ping命令其实是一个非常好的网络故障诊断工具&#xff0c;相信阅读完本文对大家一定有些帮助。如果大家网络遇到问题&#xff0c;不妨试试以下方法。首先使用Ping命令诊断本地TCP/IP协议是否安装正常&#xff0c;检测方法如下&#xff1a;从电脑开始里找到运行&#xff0c;快捷…

8.4-中断系统小结(cpu中断七个问题)

【README】 本文转自bilibili《计算机组成原理&#xff08;哈工大刘宏伟&#xff09;》的视频讲解&#xff0c;非常棒&#xff0c;墙裂推荐&#xff1b; 【1】中断介绍 1&#xff09;作用&#xff1a;用中断系统实现了外设数据的输入输出&#xff1b; 还可以用于程序调试&…

第二篇 Entity Framework Plus 之 Query Future

从性能的角度出发&#xff0c;能够减少 增&#xff0c;删&#xff0c;改&#xff0c;查&#xff0c;跟数据库打交道次数&#xff0c;肯定是对性能会有所提升的&#xff08;这里单纯是数据库部分&#xff09;。 今天主要怎样减少Entity Framework查询跟数据库打交道的次数&#…

python长整数相乘_python写的大整数相乘的方法

输入72106547548473106236 982161082972751393 两个大整数输出结果70820244829634538040848656466105986748解题思路首先根据 大整数相乘的原理的基础上&#xff0c;把大整数进行优化拆分&#xff0c;拆分的长度&#xff0c;要考虑语言中整形的长度。这里用的python&#xff0c…

Java Web应用的代码分层最佳实践

转载自 Java Web应用的代码分层最佳实践代码分层&#xff0c;对于任何一个Java Web开发来说应该都不陌生。一个好的层次划分不仅可以能使代码结构更加清楚&#xff0c;还可以使项目分工更加明确&#xff0c;可读性大大提升&#xff0c;更加有利于后期的维护和升级。从另外一个角…

中断屏蔽技术

【README】 本文总结自bilibili《计算机组成原理&#xff08;哈工大刘宏伟&#xff09;》的视频讲解&#xff0c;非常棒&#xff0c;墙裂推荐&#xff1b; 【1】中断屏蔽 1&#xff0c;中断屏蔽的意思是&#xff0c;在中断1的服务程序执行过程中&#xff0c;不允许被其他中断…

.NET FM的未来计划

2016年3月21日&#xff0c;我们启动了.NET FM这档独立播客来服务中文.NET和微软技术社区。如同早先感谢信所言&#xff0c;能够得到社区的肯定和全力支持&#xff0c;二位主播是受宠若惊。关于未来的计划&#xff0c;下面简单和大家分享一下。 首先&#xff0c;关于节目播出频率…

Java开发必须掌握的日志分析命令

转载自 Java开发必须掌握的日志分析命令 对于大型网站来说&#xff0c;很多网站在可用性方面提出4个9或者5个9的要求&#xff0c;如果是4个9&#xff0c;那么网站全年的不可用时间不能超过52.6分钟&#xff0c;如果是5个9&#xff0c;全年不可用时间不能超过5.2分钟。这其实是很…

指令寻址方式与数据寻址方式

【README】 1.本文总结自bilibili《计算机组成原理&#xff08;哈工大刘宏伟&#xff09;》的视频讲解&#xff0c;非常棒&#xff0c;墙裂推荐&#xff1b; 2. cpu访存寄存器耗费 10ns&#xff0c;访问缓存&#xff08;高速缓冲寄存器&#xff09;耗费20ns&#xff0c;访问主…

python oj 输入_Python写OJ题时输入问题

# encoding: utf-8Created on Nov 6th, 2014author: SpeedcellPython的输入是野生字符串&#xff0c;所以要自己转类型strip去掉左右两端的空白符&#xff0c;返回strslipt把字符串按空白符拆开&#xff0c;返回[str]map把list里面的值映射到指定类型&#xff0c;返回[type]EOF…

本地缓存的原理及技术选型参考

转载自 本地缓存的原理及技术选型参考互联网架构设计的五大要素&#xff1a;高性能、高可用、可伸缩性、可扩展性、安全。如何做到高性能、高可用&#xff0c;缓存是一大助力。我们知道&#xff0c;绝大部分的时候&#xff0c;读数据写数据符合二八定律。并且读数据中&#xff…

程序员欢呼:微软Bing开始支持搜索源码、可直接运行

日常生活中&#xff0c;程序员们经常会遇见这样那样的问题&#xff0c;比如忘记了代码该怎么写&#xff0c;又或者需要实现一些特殊的算法和功能。这时候&#xff0c;你就可以去找微软 Bing 帮忙啦&#xff01; 微软最近联合 HackerRank 一起研发了一项新功能&#xff1a;源代码…

rabbitmq创建缓存连接工厂

转自&#xff1a; 【RabbitMQ-3】连接池的配置_小胖学编程的博客-CSDN博客文章目录1. rabbitmq的connection连接池1.1 问题提出1.1.1 Connection对象管理以及性能1.1.2 Channel对象管理以及性能1.2 Spring AMQP线程池配置1.2.1 ConnectionFactory连接工厂1.2.2 消费发送和接收…

python简短语法_写出优雅简洁的 python 语法(二)函数传参

Python中函数传递参数的形式包含多种&#xff0c;可根据情况而定使用哪种方式。基本所有语言都有简介明了的语法去替代繁琐的代码&#xff0c;优雅的写法不仅能提升代码美观&#xff0c;更能提高提高开发效率&#xff0c;让代码更加易读。位置传递&#xff0c;默认参数位置传参…

你真的了解Java中的三目运算符吗

转载自 你真的了解Java中的三目运算符吗三目运算符是我们经常在代码中使用的&#xff0c;a (bnull?0:1);这样一行代码可以代替一个if-else,可以使代码变得清爽易读。但是&#xff0c;三目运算符也是有一定的语言规范的。在运用不恰当的时候会导致意想不到的问题。本文就介绍一…

关于.NET下开源及商业图像处理(PSD)组件

1 前言 这篇博客的背景是&#xff1a;为了完成吉日嘎拉的“PSD文件损坏检测和图层检测”任务&#xff0c;查找了目前.NET各种开源的及商业的图像处理资料&#xff0c;在完成任务之后&#xff0c;进行总结。此次任务主要是用C#操作PSD(PhotoShop)文件&#xff0c;中文资料很少&a…

SpringBoot连接多RabbitMQ源

转自&#xff1a; SpringBoot连接多RabbitMQ源 - 掘金在实际开发中&#xff0c;很多场景需要异步处理&#xff0c;这时就需要用到RabbitMQ&#xff0c;而且随着场景的增多程序可能需要连接多个RabbitMQ。SpringBoot本身提供了默认的配置可以快速配置连接RabbitMQ&#xff0c;但…

满足其中一个条件则可_农村分户好处多,但并非人人都可分户!满足这4个条件才可以申请...

分户&#xff0c;一般指子女成年或者成家后从父母户口里面独立出去&#xff0c;自立一户&#xff1b;也可以是指夫妻离婚后一方将户口独立出去(离婚也可以不分户&#xff0c;变更婚姻状态就行)。简单的说分户是指原本在一个户口本上的人口&#xff0c;现在分出去自成一个户口本…

Synchronized的实现原理(一)

转载自 Synchronized的实现原理&#xff08;一&#xff09;synchronized&#xff0c;是Java中用于解决并发情况下数据同步访问的一个很重要的关键字。当我们想要保证一个共享资源在同一时间只会被一个线程访问到时&#xff0c;我们可以在代码中使用synchronized关键字对类或者对…