解析大型.NET ERP系统 数据审计功能
2015-08-10 07:56
429 查看
数据审计,英语表达是Audit,是追踪数据变化的过程,记录数据变化前后的值,供参考分析。通过设置,ERP可以追踪一个表的所有字段的变化,也可以只记录指定的字段的值变化。欧美企业每年都有独立的审计部门,从总经理到下层部门员工,逐个审查过去发生的经济业务的帐面数据与实际是否一致。ERP中的审计功能,通常会记录下一个表字段的值的变化。ERP系统通过LLBLGenProORM框架做数据访问层,先了解ORM提供的数据审计功能。
审计功能的两个重要部分:记录的变化以及导致变化的动作,持久化变化的数据。
可用于审计的功作:
1设置属性值。与框架的一致,改变属性的值会引发OnChanged事件,但是通过设置CurrentValue的值则不会审计。
2移除对象引用。比如销售单实例不再引用客户实体,从客户集合(EntityCollection)中删除客户实体。
3增加对象引用与移除对象引用的情况相反,表示对象的属性引用到另一个对象或是实体增加到对象集合中。
4保存实体调用SaveEntity方法。
5更新实体调用SaveEntity方法。
6删除实体调用方法DeleteEntity
7获取属性值获取属性值或调用GetCurrentFieldValue方法取值,但是通过获取CurrentValue的值则不会审计。
8加载实体调用方法FetchEntity或FetchEntityCollectionNonGeneric。
定义一个枚举上面说到的八种情况:
实体基类EntityBase2已经定义以八种事件中的基础功能,一一列举如下:
1OnAuditEntityFieldSet设置属性值
2OnAuditDereferenceOfRelatedEntity移除对象引用
3OnAuditReferenceOfRelatedEntity增加对象引用
4OnAuditInsertOfNewEntity保存实体
OnAuditUpdateOfExistingEntity更新实体
5OnAuditDirectUpdateOfEntities更新实体
6OnAuditDeleteOfEntity删除实体
OnAuditDirectDeleteOfEntities删除实体
7OnAuditEntityFieldGet获取属性值
8OnAuditLoadOfEntity加载实体
创建数据库表AuditSetting表示存储数据库表是否启用审计功能(Audit)。
设计三个数据库表,用于存放数据前后的值,用于数据审计。
定义一个数据审计类型(Facade外观模式),用于数据审计操作。
因为我用的是LLBLGenPro的Adapter模式,所以为数据访问接口增加审计对象。
重写了Commit方法,这表明与数据库相关的操作事务提交时都会调用此方法,用于保存审计信息,也就是值的变化前和变化后的数据。
在保存字段数据时,注意上面的表AuditTableColumn的旧值OldValue和新值NewValue字段都是字符串类型,所以还需要写一个方法,将.NET数据类型转化为字符串格式的值。
如何获取实体属性的旧值与新值,注意上面的代码中用Commit作拦截,保存值数据,数据库事物提交时,值还没有发生更改到数据库中。对比实体的属性新值和数据库中的字段旧值,即可达到这个目的。
取旧值的方法,也就是取ORM属性字段的DbValue,LLBLGenPro这一特性在通用功能设计中非常有用。
最后上一张数据审计查询结果的界面,帮助理解审计功能的设计。
数据审计给企业的审计部门提供了方便,也会降低系统性能,频繁的记录字段的旧值和新值,增加了事务的处理时间。
对一些不重要的业务数据,应该关闭审计选项,提供系统性能。
审计功能的两个重要部分:记录的变化以及导致变化的动作,持久化变化的数据。
可用于审计的功作:
1设置属性值。与框架的一致,改变属性的值会引发OnChanged事件,但是通过设置CurrentValue的值则不会审计。
2移除对象引用。比如销售单实例不再引用客户实体,从客户集合(EntityCollection)中删除客户实体。
3增加对象引用与移除对象引用的情况相反,表示对象的属性引用到另一个对象或是实体增加到对象集合中。
4保存实体调用SaveEntity方法。
5更新实体调用SaveEntity方法。
6删除实体调用方法DeleteEntity
7获取属性值获取属性值或调用GetCurrentFieldValue方法取值,但是通过获取CurrentValue的值则不会审计。
8加载实体调用方法FetchEntity或FetchEntityCollectionNonGeneric。
定义一个枚举上面说到的八种情况:
publicenumAuditType { DeleteOfEntity=1, DirectDeleteOfEntities, DirectUpdateOfEntities, DereferenceOfRelatedEntity, ReferenceOfRelatedEntity, EntityFieldSet, InsertOfNewEntity, UpdateOfExistingEntity }
实体基类EntityBase2已经定义以八种事件中的基础功能,一一列举如下:
1OnAuditEntityFieldSet设置属性值
2OnAuditDereferenceOfRelatedEntity移除对象引用
3OnAuditReferenceOfRelatedEntity增加对象引用
4OnAuditInsertOfNewEntity保存实体
OnAuditUpdateOfExistingEntity更新实体
5OnAuditDirectUpdateOfEntities更新实体
6OnAuditDeleteOfEntity删除实体
OnAuditDirectDeleteOfEntities删除实体
7OnAuditEntityFieldGet获取属性值
8OnAuditLoadOfEntity加载实体
创建数据库表AuditSetting表示存储数据库表是否启用审计功能(Audit)。
CREATETABLE[dbo].[AuditSetting]( [TableName][NVARCHAR](100)NOTNULL, CONSTRAINT[PK_AuditSetting]PRIMARYKEYCLUSTERED ( [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记录用户在每个时间点操作了什么功能 CREATETABLE[dbo].[Audit] ( [LogNo][bigint]NOTNULLIDENTITY(1,1), [Date][datetime]NULL, [UserId][nvarchar](10)COLLATESQL_Latin1_General_CP1_CI_ASNULL, [FunctionCode][nvarchar](8)COLLATESQL_Latin1_General_CP1_CI_ASNULL, [Remarks][nvarchar](100)COLLATESQL_Latin1_General_CP1_CI_ASNULL )ON[PRIMARY] GO ALTERTABLE[dbo].[Audit]ADDCONSTRAINT[PK_Audit]PRIMARYKEYCLUSTERED([LogNo])WITH(FILLFACTOR=70)ON[PRIMARY] GO --AuditTable记录用户操作的功能涉及到的表 CREATETABLE[dbo].[AuditTable] ( [LogNo][bigint]NOTNULL, [TableNo][int]NOTNULL, [Action][int]NULL, [EntityName][nvarchar](60)COLLATESQL_Latin1_General_CP1_CI_ASNULL, [KeyValue][nvarchar](200)COLLATESQL_Latin1_General_CP1_CI_ASNULL )ON[PRIMARY] GO ALTERTABLE[dbo].[AuditTable]ADDCONSTRAINT[PK_AuditTable]PRIMARYKEYCLUSTERED([LogNo],[TableNo])WITH(FILLFACTOR=70)ON[PRIMARY] GO ALTERTABLE[dbo].[AuditTable]WITHNOCHECKADDCONSTRAINT[FK_AuditTrailTableDetail_AuditTrail]FOREIGNKEY([LogNo])REFERENCES[dbo].[Audit]([LogNo])ONDELETECASCADEONUPDATECASCADE GO --AuditTablecolumndetail记录列值的新值和旧值 CREATETABLE[dbo].[AuditTableColumn] ( [LogNo][bigint]NOTNULL, [TableNo][int]NOTNULL, [ColumnNo][int]NOTNULL, [ColumnName][nvarchar](100)COLLATESQL_Latin1_General_CP1_CI_ASNOTNULL, [OldValue][ntext]COLLATESQL_Latin1_General_CP1_CI_ASNULL, [NewValue][ntext]COLLATESQL_Latin1_General_CP1_CI_ASNULL )ON[PRIMARY]TEXTIMAGE_ON[PRIMARY] GO ALTERTABLE[dbo].[AuditTableColumn]ADDCONSTRAINT[PK_AuditTrailColumnDetail]PRIMARYKEYCLUSTERED([LogNo],[TableNo],[ColumnNo])WITH(FILLFACTOR=70)ON[PRIMARY] GO ALTERTABLE[dbo].[AuditTableColumn]WITHNOCHECKADDCONSTRAINT[FK_AuditTrailColumnDetail_AuditTrailTableDetail]FOREIGNKEY([LogNo],[TableNo])REFERENCES[dbo].[AuditTable]([LogNo],[TableNo])ONDELETECASCADEONUPDATECASCADE GO
定义一个数据审计类型(Facade外观模式),用于数据审计操作。
[DependencyInjectionInfo(typeof(IEntity2),"AuditorToUse")]
[Serializable]
publicsealedclassDatabaseAuditor:AuditorBase,IDisposable
{
#regionClassMemberDeclarations
privateAuditEntity_auditTrail;
privateAuditTableCollection_auditTrailTableDetails;
因为我用的是LLBLGenPro的Adapter模式,所以为数据访问接口增加审计对象。
publicsealedclassDataAccessAdapter
{
privateDatabaseAuditor_auditor;
privatevoidInitilaizeAuditor(IEntity2entity)
{
_auditor=newDatabaseAuditor();
_auditor.Adapter=this;
}
protectedoverridevoidDispose(boolisDisposing)
{
if(_auditor!=null)
{
_auditor.Dispose();
_auditor=null;
}
}
publicoverridevoidCommit()
{
if(_auditor!=null)
{
_auditor.PersistAuditInfo();
_auditor.Dispose();
_auditor=null;
}
}
}
重写了Commit方法,这表明与数据库相关的操作事务提交时都会调用此方法,用于保存审计信息,也就是值的变化前和变化后的数据。
在保存字段数据时,注意上面的表AuditTableColumn的旧值OldValue和新值NewValue字段都是字符串类型,所以还需要写一个方法,将.NET数据类型转化为字符串格式的值。
如何获取实体属性的旧值与新值,注意上面的代码中用Commit作拦截,保存值数据,数据库事物提交时,值还没有发生更改到数据库中。对比实体的属性新值和数据库中的字段旧值,即可达到这个目的。
foreach(IEntityField2fieldinentity).Fields)
{
stringoriginalValue=GetFieldOriginalValue(field,false);
stringcurrentValue=GetFieldCurrentValue(field,false);
}
取旧值的方法,也就是取ORM属性字段的DbValue,LLBLGenPro这一特性在通用功能设计中非常有用。
stringfieldOldValue=string.Empty;
if(field.DbValue!=null&&field.DbValue!=DBNull.Value)
{
fieldOldValue=ConvertValueToString(field.DbValue,convertZeroToEmptyString);
}
最后上一张数据审计查询结果的界面,帮助理解审计功能的设计。
数据审计给企业的审计部门提供了方便,也会降低系统性能,频繁的记录字段的旧值和新值,增加了事务的处理时间。
对一些不重要的业务数据,应该关闭审计选项,提供系统性能。
相关文章推荐
- DATABASE LINK 的查看、创建与删除
- hdoj1176免费馅饼【dp】
- POJ 2411 Mondriaan's Dream
- 网桥和网桥相连的网络
- Android自定义组合控件的实现
- 新手应知应会的Linux命令
- 信号
- 信号
- 【LeetCode-面试算法经典-Java实现】【109-Convert Sorted List to Binary Search Tree(排序链表转换成二叉排序树)】
- PHP关闭Notice错误提示
- php提取字符串中的数字
- 【LeetCode-面试算法经典-Java实现】【108-Convert Sorted Array to Binary Search Tree(排序数组转变为平衡二叉树)】
- 由大到小排列
- 冒泡排序法 ,由小到大排列
- 第五篇 SQL Server安全架构和安全
- 【LeetCode-面试算法经典-Java实现】【107-Binary Tree Level Order Traversal II(二叉树层序遍历II)】
- 开源中国源码学习(五)——切换皮肤(日间模式和夜间模式)
- OSChina 周一乱弹 —— 程序员进阶之路
- LeetCode 152 - Maximum Product Subarray
- *Validate Binary Search Tree