Winform开发框架的权管理体系改进的经验总结(4)-一行代码实现表操作日志记录

当头里介绍了几乎篇有关我之权位系统改进的一部分经验总结,本篇继续就无异于系列主体,介绍如何一实施代码实现重要表的操作日志记录。我们领略,在无数业务系统间,数据是充分敏感的,特别对有增加、修改、删除等根本之操作,如果会于框架层面的支持基础及,以极其少之代码实现重要表的日记记录,那么是一模一样起十分值得庆贺的事情,也会为我们客户的多寡提供至关重要之日记跟踪,甚至是数据恢复的参阅。

1、数据访问层的目标继承关系

率先,为了减少重复代码的编,合理之接续关系是必需之,我们需要在数码访问层及成立合理之累关系,如下是我的Winform开发框架的后续关系。每个数据看对象(如ItemDetail数据访问对象)都延续一个虚幻基类AbstractBaseDAL和一个IBaseDAL基类接口,同时其吗起温馨特别之作业接口,如IItemDetail,关系如下所示。

bifa365必发 1

来了上面的累关系,我们尽管可以把正常的数据库重点操作(增删改)放到一个胜似一级的层次上解决之问题,而休需要在每个数据访问层的事情类似来贯彻。

2、操作日志记录事件之概念及运用

为了重新好实现数量操作日志的笔录,我们盖事件方来点操作日志的记录,事件之切实记录实现,可以付出外部来记录处理。如果事件被标赋值了,那么就是足以于底部触发这个事件记录,记录事件之定义代码在空洞基类进行定义,如下所示。

    /// 定义一个记录操作日志的事件处理
    /// </summary>
    /// <param name="userId">操作的用户ID</param>
    /// <param name="tableName">操作表名称</param>
    /// <param name="operationType">操作类型:增加、修改、删除</param>
    /// <param name="note">操作的详细记录信息</param>
    /// <returns></returns>
    public delegate bool OperationLogEventHandler(string userId, string tableName, string operationType, string note, DbTransaction trans = null); 

    /// <summary>
    /// 数据访问层的超级基类,所有数据库的数据访问基类都继承自这个超级基类,包括Oracle、SqlServer、Sqlite、MySql、Access等
    /// </summary>
    public abstract class AbstractBaseDAL<T> where T : BaseEntity, new()
    {
        #region 构造函数

        protected string dbConfigName = ""; //数据库配置名称
        protected string parameterPrefix = "@";//数据库参数化访问的占位符
        protected string safeFieldFormat = "[{0}]";//防止和保留字、关键字同名的字段格式,如[value]
        protected string tableName;//需要初始化的对象表名
        protected string primaryKey;//数据库的主键字段名
        protected string sortField;//排序字段
        protected bool isDescending = true;//是否为降序
        protected string selectedFields = " * ";//选择的字段,默认为所有(*)        
        public event OperationLogEventHandler OnOperationLog;//定义一个操作记录的事件处理

.....................

上述是空虚基类AbstractBaseDAL的有的代码,上面代码定义了一个操作记录的委托以及波目标来拍卖操作日志的笔录,通过委托的定义,我们可确定实际的事件接口定义,并于架空基类的根构造这些参数的数值,传递给外部的靶子进行处理。

那我们是什么样在脚操作构造这些信息之啊?

骨子里就算是当对应的显要操作接口函数上调用这个定义之风波。我们好当虚幻基类的插入、修改、删除等接口上调用事件进展处理即可,为了重新好处理有关数据的布局逻辑,我们把调用OnOperationLog的事件封装到一个独的函数里面进行拍卖,如下所示是底层更新操作的代码,通过长一个OperationLogOfUpdate来促成数据日志的事件处理。

        /// <summary>
        /// 更新对象属性到数据库中
        /// </summary>
        /// <param name="obj">指定的对象</param>
        /// <param name="primaryKeyValue">主键的值</param>
        /// <param name="trans">事务对象</param>
        /// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
        public virtual bool Update(T obj, object primaryKeyValue, DbTransaction trans = null)
        {
            ArgumentValidation.CheckForNullReference(obj, "传入的对象obj为空");

            OperationLogOfUpdate(obj, primaryKeyValue, trans);//根据设置记录操作日志

            Hashtable hash = GetHashByEntity(obj);
            return Update(primaryKeyValue, hash, trans);
        }

接下来我们在切实可行的事件处理封装函数OnOperationLog的内添加处理逻辑即可,一般事件之科班处理吧如下代码。

        /// <summary>
        /// 修改操作的日志记录
        /// </summary>
        /// <param name="id">记录ID</param>
        /// <param name="obj">数据对象</param>
        /// <param name="trans">事务对象</param>
        protected virtual void OperationLogOfUpdate(T obj, object id, DbTransaction trans = null)
        {
            if (OnOperationLog != null)
            {
                    ...............................//构造相关参数
                    OnOperationLog(userId, this.tableName, operationType, note, trans);
                }
            }
        }

咱们掌握,一般操作日志都见面记录是谁进行操作的,然后将它写到日志中,并把操作的情而读化即可,那么以更新的时,我们怎么知道是何人操作的靶子为?因为咱们从不传递具体的用户ID等标识的哎。

其一题材挺头痛,如果长多一个参数,那么就算得改很多息息相关的调用逻辑,这个肯定不太适合我们简要的品格,因此最好好外觅其他方法来落实之人员地位记录之题目。

咱们懂得,一般插入、更新操作,都是带来一个操作对象的,这个操作对象是一个实体类,基类是BaseEntity,那么我们可以在它的随身定义多一个属性,这个特性不参数数据的保存,只是作为参数的传递及辨识而已,实体类基类的代码如下所示。

    /// <summary>
    /// 框架实体类的基类
    /// </summary>
    [DataContract]
    public class BaseEntity
    {
        private string m_CurrentLoginUserId;

        /// <summary>
        /// 当前登录用户ID。该字段不保存到数据表中,只用于记录用户的操作日志。
        /// </summary>
        [DataMember]
        public string CurrentLoginUserId
        {
            get { return m_CurrentLoginUserId; }
            set { m_CurrentLoginUserId = value; }
        }
    }
}

出了此消息,我们就是得以方的事件处理逻辑上展开得用户的ID操作了。

string userId = obj.CurrentLoginUserId;

生一个题目是,如何把操作的消息但读化,我们知晓,一般操作只是对一些配段进展修改,那么我们一般也未待拿具有的字段信息还作出来展示,只待出示那些修改的即可。

为兑现这数的差异化显示,我们要以创新操作前进行获取数据库的对象信息,然后跟将进行翻新的靶子进行对比,把差异的信息作备注信息记录下来即可,具体逻辑如下所示。

        /// <summary>
        /// 修改操作的日志记录
        /// </summary>
        /// <param name="id">记录ID</param>
        /// <param name="obj">数据对象</param>
        /// <param name="trans">事务对象</param>
        protected virtual void OperationLogOfUpdate(T obj, object id, DbTransaction trans = null)
        {
            if (OnOperationLog != null)
            {
                string operationType = "修改";
                string userId = obj.CurrentLoginUserId;

                Hashtable recordField = GetHashByEntity(obj);
                Dictionary<string, string> dictColumnNameAlias = GetColumnNameAlias();

                T objInDb = FindByID(id, trans);
                if (objInDb != null)
                {
                    Hashtable dbrecordField = GetHashByEntity(objInDb);//把数据库里的实体对象数据转换为哈希表

                    StringBuilder sb = new StringBuilder();
                    foreach (string field in recordField.Keys)
                    {                          
                        string newValue = recordField[field].ToString();
                        string oldValue = dbrecordField[field].ToString();
                        if (newValue != oldValue)//只记录变化的内容
                        {                            
                            string columnAlias = "";
                            bool result = dictColumnNameAlias.TryGetValue(field, out columnAlias);
                            if (result && !string.IsNullOrEmpty(columnAlias))
                            {
                                columnAlias = string.Format("({0})", columnAlias);//字段中文名称前,增加一个括号显示,方便区分显示
                            }

                            sb.AppendLine(string.Format("{0}{1}:", field, columnAlias));
                            sb.AppendLine(string.Format("\t {0} -> {1}", dbrecordField[field], recordField[field]));
                            sb.AppendLine();
                        }
                    }
                    sb.AppendLine();
                    string note = sb.ToString();

                    OnOperationLog(userId, this.tableName, operationType, note, trans);
                }
            }
        }

面是翻新操作的日志记录处理,其他的插入、删除等操作看似这样的操作方法,再次不以赘述。

3、业务层对操作日志信息之处理

地方的代码只是实现了针对性根操作的消息记录并传递给操作日志的记录事件,并从未清楚上层是什么样处理事件信息之笔录的,这个题材留给上层去处理。

为落实之消息的笔录,我们以权力系统之中加一个单身的数据库表如T_ACL_OperationLog表用来专门记录这些消息的。

bifa365必发 2

上层之处理逻辑是收获用户ID的登陆信息,包括用户称、用户IP地址、Mac地址信息等,这些消息而用户登陆到系统即会见来了,所以可以好得到,然后便拿这些消息作一个数据库记录写副数据库表即可。

                    OperationLogInfo info = new OperationLogInfo();
                    info.TableName = tableName;
                    info.OperationType = operationType;
                    info.Note = note;
                    info.CreateTime = DateTime.Now;

                    if (!string.IsNullOrEmpty(userId))
                    {
                        UserInfo userInfo = BLLFactory<User>.Instance.FindByID(userId, trans);
                        if (userInfo != null)
                        {
                            info.User_ID = userId;
                            info.LoginName = userInfo.Name;
                            info.FullName = userInfo.FullName;
                            info.Company_ID = userInfo.Company_ID;
                            info.CompanyName = userInfo.CompanyName;
                            info.MacAddress = userInfo.CurrentMacAddress;
                            info.IPAddress = userInfo.CurrentLoginIP;
                        }
                    }

                    return BLLFactory<OperationLog>.Instance.Insert(info, trans);

因这些记录之操作都是一样的,为了重新便于,我们将这些逻辑封装于一个静态的不二法门中,然后所有需要记录操作日志的,在工作对象中长一行代码,就足以轻松实现日志记录了,具体代码如下所示。

    /// <summary>
    /// 部门机构信息
    /// </summary>
    public class OU : BaseBLL<OUInfo>
    {
        private IOU ouDal;

        /// <summary>
        /// 构造函数
        /// </summary>
        public OU() : base()
        {
            base.Init(this.GetType().FullName, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
            baseDal.OnOperationLog += new OperationLogEventHandler(WHC.Security.BLL.OperationLog.OnOperationLog);//如果需要记录操作日志,则实现这个事件

            this.ouDal = baseDal as IOU;
        }

诸如此类数据访问类baseDal一旦事件初始化,那么就会于脚进行接触,然后交到事件之处理逻辑(上层操作)进行拍卖了。

为还好控制用户之加、修改、删除的相关事件,我们得经一个布局表展开注册处理,然后根据配置表的参数来控制记录那些信息,这些就是是细化的题目了。

4、我之Winform开发框架的权限系统模块里面对操作日志的支撑

于自身的Winform开发框架中,权限系统是内部的一个基础部分,因此呢根据上面的逻辑实现了对操作日志的参数配置以及著录显示,方便对事情体系所有表的操作记录进行跟踪及拍卖。

经过一行代码就能够实现业务表的日志记录,对我们开发新的工作模块,效率可以增长广大,同时也克叫客户提供再好的数量支持服务。通过当权力系统bifa365必发模块里面配备参数和出示操作日志记录,能够给业务支付提供基础性的开支框架支持。

脚是自己的Winform开发框架的权柄系统模块的片段功能 截图,供参考学习。

bifa365必发 3

双击打开记录之精雕细刻,可以看到操作记录的有心人显示。

bifa365必发 4

参数配置界面如下所示。

bifa365必发 5

以上显示只有是基于权限系统进行日志的笔录,当然整个事情体系框架还可以提供点的记录操作,因为它们有的数码访问基类都是累自同一个虚幻对象基类的。把这个模块并在权力系统间,和登陆日志一样,是供基础性的记录和查阅的,和作业不绝相关。 

末附上Winform开发框架的一个效果总结图形,Winform开发框架的主要力量概览如下图所示。

bifa365必发 6

发表评论

电子邮件地址不会被公开。 必填项已用*标注