数据审计,英语表达是Audit,是追踪数据变化的过程,记录数据变化前后的值,供参考分析。通过设置,ERP可以追踪一个表的所有字段的变化,也可以只记录指定的字段的值变化。欧美企业每年都有独立的审计部门,从总经理到下层部门员工,逐个审查过去发生的经济业务的帐面数据与实际是否一致。ERP中的审计功能,通常会记录下一个表字段的值的变化。ERP系统通过LLBL Gen Pro ORM框架做数据访问层,先了解ORM提供的数据审计功能。

审计功能的两个重要部分:记录的变化以及导致变化的动作,持久化变化的数据。

可用于审计的功作:

1 设置属性值。与框架的一致,改变属性的值会引发OnChanged事件,但是通过设置CurrentValue的值则不会审计。

2 移除对象引用。比如销售单实例不再引用客户实体,从客户集合(EntityCollection)中删除客户实体。

3 增加对象引用  与移除对象引用的情况相反,表示对象的属性引用到另一个对象或是实体增加到对象集合中。

4 保存实体  调用SaveEntity方法。

5 更新实体 调用SaveEntity方法。

6 删除实体 调用方法DeleteEntity

7  获取属性值 获取属性值或调用GetCurrentFieldValue方法取值,但是通过获取CurrentValue的值则不会审计。

8  加载实体 调用方法FetchEntity或FetchEntityCollectionNonGeneric。

定义一个枚举上面说到的八种情况:

public enum AuditType
{
DeleteOfEntity=1,
DirectDeleteOfEntities,
DirectUpdateOfEntities,
DereferenceOfRelatedEntity,
ReferenceOfRelatedEntity,
EntityFieldSet,
InsertOfNewEntity,
UpdateOfExistingEntity
}

实体基类EntityBase2已经定义以八种事件中的基础功能,一一列举如下:

1 OnAuditEntityFieldSet 设置属性值

2 OnAuditDereferenceOfRelatedEntity移除对象引用

3 OnAuditReferenceOfRelatedEntity 增加对象引用

4 OnAuditInsertOfNewEntity保存实体

OnAuditUpdateOfExistingEntity更新实体

5 OnAuditDirectUpdateOfEntities 更新实体

6 OnAuditDeleteOfEntity 删除实体

OnAuditDirectDeleteOfEntities 删除实体

7 OnAuditEntityFieldGet获取属性值

8 OnAuditLoadOfEntity加载实体

创建数据库表AuditSetting 表示存储数据库表是否启用审计功能(Audit)。

CREATE TABLE [dbo].[AuditSetting](
[TableName] [NVARCHAR](100) NOT NULL,
CONSTRAINT [PK_AuditSetting] PRIMARY KEY CLUSTERED
(
[EntityName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] GO

设计三个数据库表,用于存放数据前后的值,用于数据审计。

--Audit  记录用户在每个时间点操作了什么功能
CREATE TABLE [dbo].[Audit]
(
[LogNo] [bigint] NOT NULL IDENTITY(1, 1),
[Date] [datetime] NULL,
[UserId] [nvarchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[FunctionCode] [nvarchar] (8) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Remarks] [nvarchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO ALTER TABLE [dbo].[Audit] ADD CONSTRAINT [PK_Audit] PRIMARY KEY CLUSTERED ([LogNo]) WITH (FILLFACTOR=70) ON [PRIMARY]
GO --Audit Table 记录用户操作的功能涉及到的表
CREATE TABLE [dbo].[AuditTable]
(
[LogNo] [bigint] NOT NULL,
[TableNo] [int] NOT NULL,
[Action] [int] NULL,
[EntityName] [nvarchar] (60) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[KeyValue] [nvarchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[AuditTable] ADD CONSTRAINT [PK_AuditTable] PRIMARY KEY CLUSTERED ([LogNo], [TableNo]) WITH (FILLFACTOR=70) ON [PRIMARY]
GO ALTER TABLE [dbo].[AuditTable] WITH NOCHECK ADD CONSTRAINT [FK_AuditTrailTableDetail_AuditTrail] FOREIGN KEY ([LogNo]) REFERENCES [dbo].[Audit] ([LogNo]) ON DELETE CASCADE ON UPDATE CASCADE
GO --Audit Table column detail 记录列值的新值和旧值
CREATE TABLE [dbo].[AuditTableColumn]
(
[LogNo] [bigint] NOT NULL,
[TableNo] [int] NOT NULL,
[ColumnNo] [int] NOT NULL,
[ColumnName] [nvarchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[OldValue] [ntext] COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[NewValue] [ntext] COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[AuditTableColumn] ADD CONSTRAINT [PK_AuditTrailColumnDetail] PRIMARY KEY CLUSTERED ([LogNo], [TableNo], [ColumnNo]) WITH (FILLFACTOR=70) ON [PRIMARY]
GO
ALTER TABLE [dbo].[AuditTableColumn] WITH NOCHECK ADD CONSTRAINT [FK_AuditTrailColumnDetail_AuditTrailTableDetail] FOREIGN KEY ([LogNo], [TableNo]) REFERENCES [dbo].[AuditTable] ([LogNo], [TableNo]) ON DELETE CASCADE ON UPDATE CASCADE
GO
 

定义一个数据审计类型(Facade外观模式),用于数据审计操作。

[DependencyInjectionInfo(typeof(IEntity2), "AuditorToUse")]
[Serializable]
public sealed class DatabaseAuditor : AuditorBase, IDisposable
{
#region Class Member Declarations
private AuditEntity _auditTrail;
private AuditTableCollection _auditTrailTableDetails;

因为我用的是LLBL Gen Pro的Adapter模式,所以为数据访问接口增加审计对象。

public sealed class DataAccessAdapter
{
private DatabaseAuditor _auditor; private void InitilaizeAuditor(IEntity2 entity)
{
_auditor = new DatabaseAuditor();
_auditor.Adapter = this;
} protected override void Dispose(bool isDisposing)
{
if (_auditor != null)
{
_auditor.Dispose();
_auditor = null;
}
     }

     public override void Commit()
{
if (_auditor != null)
{
_auditor.PersistAuditInfo();
_auditor.Dispose();
_auditor = null;
}
     }
}
 
 

重写了Commit方法,这表明与数据库相关的操作事务提交时都会调用此方法,用于保存审计信息,也就是值的变化前和变化后的数据。

在保存字段数据时,注意上面的表AuditTableColumn的旧值OldValue和新值NewValue字段都是字符串类型,所以还需要写一个方法,将.NET数据类型转化为字符串格式的值。

如何获取实体属性的旧值与新值,注意上面的代码中用Commit作拦截,保存值数据,数据库事物提交时,值还没有发生更改到数据库中。对比实体的属性新值和数据库中的字段旧值,即可达到这个目的。

foreach (IEntityField2 field in  entity).Fields)
{
string originalValue = GetFieldOriginalValue(field, false);
string currentValue = GetFieldCurrentValue(field, false);
}

取旧值的方法,也就是取ORM属性字段的DbValue,LLBL Gen Pro这一特性在通用功能设计中非常有用。

string fieldOldValue=string.Empty;
if (field.DbValue != null && field.DbValue != DBNull.Value)
{
fieldOldValue= ConvertValueToString(field.DbValue, convertZeroToEmptyString);
}
 

最后上一张数据审计查询结果的界面,帮助理解审计功能的设计。

数据审计给企业的审计部门提供了方便,也会降低系统性能,频繁的记录字段的旧值和新值,增加了事务的处理时间。

对一些不重要的业务数据,应该关闭审计选项,提供系统性能。

解析大型.NET ERP系统 数据审计功能的更多相关文章

  1. 解析大型.NET ERP系统 单据编码功能实现

    单据编码是ERP系统中必备的功能,用于生成各种单据的流水号,常常借助于日期时间等字符来生成一个唯一的单据号码.从软件的角度来说,就是为生成数据表的主键值(参考编号),从用户的角度来说,就是给业务单据制 ...

  2. 解析大型.NET ERP系统数据访问 对象关系映射框架LLBL Gen Pro

    LLBL Gen Pro是一个为.NET开发人员设计的的对象关系映射(ORM)框架,与NHibernate,Entity Framework等框架一样,通过实体与数据表的映射,实现关系数据库持久化. ...

  3. 解析大型.NET ERP系统 十三种界面设计模式

    成熟的ERP系统的界面应该都是从模板中拷贝出来的,各类功能的界面有规律可遵循.软件界面设计模式化或是艺术性的创作,我认可前者,模式化的界面客户容易举一反三,降低学习门槛.除了一些小部分的功能界面设计特 ...

  4. 解析大型.NET ERP系统 通用附件管理功能

    大型系统具备一个通用的附件管理功能,对于单据中无法清晰表达的字段,用一个附件图片或附件文档表示是最好的方法了.比如物料清单附加一张CAD图纸,销售订单评审功能中附加客户的各种表格,通用附件功能对系统起 ...

  5. 解析大型.NET ERP系统 单据标准(新增,修改,删除,复制,打印)功能程序设计

    ERP系统的单据具备标准的功能,这里的单据可翻译为Bill,Document,Entry,具备相似的工具条操作界面.通过设计可复用的基类,子类只需要继承基类窗体即可完成单据功能的程序设计.先看标准的销 ...

  6. 解析大型.NET ERP系统 设计通用Microsoft Excel导入功能

    做企业管理软件很难避免与Microsoft Excel打交道,常常是软件做好了,客户要求说再做一个Excel导入功能.导入Excel数据的功能的难度不大,从Excel列数据栏位的取值,验证值,再导入到 ...

  7. 解析大型.NET ERP系统架构设计 Framework+ Application 设计模式

    我对大型系统的理解,从数量上面来讲,源代码超过百万行以上,系统有超过300个以上的功能,从质量上来讲系统应该具备良好的可扩展性和可维护性,系统中的功能紧密关联.除去业务上的复杂性,如何设计这样的一个协 ...

  8. 解析大型.NET ERP系统 权限模块设计与实现

    权限模块是ERP系统的核心模块之一,完善的权限控制机制给系统增色不少.总结我接触过的权限模块,以享读者. 1 权限的简明定义 ERP权限管理用一句简单的话来说就是:谁 能否 做 那些 事. 文句 含义 ...

  9. 解析大型.NET ERP系统 设计异常处理模块

    异常处理模块是大型系统必备的一个组件,精心设计的异常处理模块可提高系统的健壮性.下面从我理解的角度,谈谈异常处理的方方面面.我的设计仅仅限定于Windows Forms,供参考. 1 定义异常类型 . ...

随机推荐

  1. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

  2. 【原】nodejs全局安装和本地安装的区别

    来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...

  3. 零OCR基础6行代码实现C#验证码识别

    这两天因为工作需要,要到某个网站采集信息,一是要模拟登陆,二是要破解验证码,本想用第三方付费打码,但是想想网上免费的代码也挺多的,于是乎准备从网上撸点代码下来,谁知道,撸了好多个都不行,本人以前也没接 ...

  4. .Net语言 APP开发平台——Smobiler学习日志:如何快速在手机上实现ContextMenu

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 样式一 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的&qu ...

  5. JAVA回调机制解析

    一.回调机制概述     回调机制在JAVA代码中一直遇到,但之前不懂其原理,几乎都是绕着走.俗话说做不愿意做的事情叫做突破,故诞生了该文章,算是新年的新气象,新突破!     回调机制是什么?其实回 ...

  6. SharePoint 2016 必备组件离线安装介绍

    前言 SharePoint 必备组件安装,一直以来都是SharePoint安装过程中的最大的坑,尤其是不能联网的服务器.博主在这里简单介绍一下离线安装过程,并附组件包下载以及安装命令,并且在windo ...

  7. RMS Server打开或关闭日志记录

    原文: https://technet.microsoft.com/zh-cn/library/cc732758 在 Active Directory Rights Management Servic ...

  8. AEAI DP V3.6.0 升级说明,开源综合应用开发平台

    AEAI DP综合应用开发平台是一款扩展开发工具,专门用于开发MIS类的Java Web应用,本次发版的AEAI DP_v3.6.0版本为AEAI DP _v3.5.0版本的升级版本,该产品现已开源并 ...

  9. HA 高可用软件系统保养指南

    又过了一年 618,六月是公司一年一度的大促月,一般提前一个月各系统就会减少需求和功能的开发,转而更多去关注系统可用性.稳定性和管控性等方面的非功能需求.大促前的准备工作一般叫作「备战」,可以把线上运 ...

  10. Linux虚拟化学习笔记<一>

    关于虚拟化,原理的东西是非常复杂的,要想完全理解,没有足够的耐心是不不能完全学透这部分内容的.那下面我主要以资源汇总的形式把一些资料罗列出来,帮助大家快速理解虚拟化,快速使用和配置. 为什么要虚拟化: ...