数据库
首页 > 数据库> > 基于FreeSql和AutoMapper实现可读性较高的审计追踪

基于FreeSql和AutoMapper实现可读性较高的审计追踪

作者:互联网

基础概念

系统内对数据的操作通过数据库实体保存到库,通过数据库实体我们可以获取到变化之前的数据和变化之后的数据,但是基于数据库实体记录审计追踪有很大的弊病。

数据库实体的结构是基于业务需要设计的,一般很难满足审计追踪的观赏性方面的需求,要么是多出很多用户看不懂的字段,如主键、版本号等;要么是缺少必要的解释字段,比如有用户ID但是没有用户姓名。

审计追踪DTO

为了可以控制审计追踪记录的内容,需要新建一个专用于审计追踪的DTO,去掉不希望展示给用户的字段,加上必要的解释字段,例:

    public class DeviceAuditDto : TKey
    {
        /// <summary>
        /// 名称
        /// </summary>
        [Description("名称")]
        [GroupField]
        public string Name { get; set; }

        /// <summary>
        /// 设备类型(字典)
        /// </summary>
        [Description("设备类型(字典)")]
        public string DeviceType { get; set; }

        /// <summary>
        /// 设备型号
        /// </summary>
        [Description("设备型号")]
        public string DeviceModel { get; set; }
    }

在本系统中,为了标记审计追踪专属DTO,都需要继承自TKey

字段属性Description的内容会做为字段含义显示在前端,便于用户理解

字段属性GroupField表示该字段是数据的标识性字段,记录多条数据的审计时,会以这个字段分组

编写审计追踪的几种方式

1、自动获取变化数据的

这种方式利用了FreeSql的实体变化追踪特性,编写审计追踪代码时,不需要传入实体的变化前数据和变化后数据,而是根据FreeSql已经追踪的数据自动记录到数据库。使用者只需要传入本次操作的模块、动作、操作内容。代码如下

            //记录审计追踪
            var InspAuditDto = new AutoAuditTrailDto()
            {
                BusinessId = BusinessAuditConsts.TestConditionAudit_BusniessId,
                OperateType = ActionTypeEnum.Register.Description(),
                Detail = string.Format(tips["StaticData.SignUpTestCondition"], entities.Select(e => e.ProductNo).Distinct().ToArray().Join())
            };
            await gxpAuditTrailService.Handle(InspAuditDto);

使用这种方式有一些限制条件:

  1. 方法需要有【Transaction】属性,整个方法处在事务中
  2. 变化的实体数据已经被FreeSql追踪,如果使用了UpdateDiy、ToUpdate等不会追踪变化的FreeSql功能,将无法正确获取变化前后的实体数据
  3. 数据库实体一定要通过AutoMapper映射到对应的AuditDto
  4. 实体中包含所需要记录的全部数据。例,如果实体中有用户Id但是没有用户姓名,那么就不适合使用本方法,需要手动处理实体数据

2、手动记录单表的审计追踪

该方法需要自己传入变化前后的数据,例:

	    // 记录审计追踪
            var auditDto = new BaseAuditTrailDto<BuildingAuditDto, ActionTypeEnum>()
            {
                BusinessId = "Warehouse.BusinessId",
                BusinessType = "Building.BusinessType",
                OperateType = ActionTypeEnum.Update,
                Detail = string.Format(tips["Building.UpdateDetail"], entity.Code),
                PreEntity = new List<BuildingAuditDto>
                {
                    mapper.Map<BuildingAuditDto>(oldEntity)
                },
                NewEntity = new List<BuildingAuditDto>
                {
                    mapper.Map<BuildingAuditDto>(entity)
                }
            };

入参中的NewEntity就是变化后的实体,PreEntity是变化前的实体,采用该方法可以记录单表的审计追踪,且数据在传入之前,可以进行手动的修改、赋值。

获取变化数据的扩展方法

为了便捷的获取变化前后的实体,在仓储层基类FreeSqlRepositoryBase中实现了快速获取变化前后数据的方法,获取到的数据已经转化为了对应的AuditDto,所以需要传入AuditDto对应的泛型和AutoMapper对象,如下:

	    //记录审计追踪
            var InspAuditDto = new BaseAuditTrailDto<TestConditionAuditDto, ActionTypeEnum>()
            {
                BusinessId = BusinessAuditConsts.TestConditionAudit_BusniessId,
                OperateType = ActionTypeEnum.CancelRegister,
                Detail = string.Format(tips["StaticData.CancelSignUpTestCondition"], entities.Select(e => e.ProductNo).Distinct().ToArray().Join()),
                NewEntity = testConditionRepository.GetNewAuditList<TestConditionAuditDto>(mapper),
                PreEntity = testConditionRepository.GetBeforeAuditList<TestConditionAuditDto>(mapper)
            };
            await gxpAuditTrailService.Handle(InspAuditDto);

由于该方法利用也是FreeSql的特性,所以也需要满足上述1、2、3条限制才可以使用。

3、手动记录多表的审计追踪

该方式与方式2差不多,主要是处理不能使用方式1,又涉及到多表的情况,代码如下:

	    #region 审计追踪
            var InspAuditDto = new AggregateAuditTrailDto<TestConditionAuditDto, StabilityPlanAuditDto, StabilityAuditDto, ActionTypeEnum>()
            var InspAuditDto = new AutoAuditTrailDto()
            {
                BusinessId = BusinessAuditConsts.TestConditionAudit_BusniessId,
                BusinessType = BusinessAuditConsts.TestConditionAudit_BusniessType,
                OperateType = ActionTypeEnum.RegisterStart,
                AuditEntity = new AggregateAuditEntity<TestConditionAuditDto>
                {
                    NewEntities = mapper.Map<List<TestConditionAuditDto>>(entities),
                    PreEntities = preList
                },
                SecondAuditEntity = new AggregateAuditEntity<StabilityPlanAuditDto>
                {
                    NewEntities = mapper.Map<List<StabilityPlanAuditDto>>(stabPlans)
                },
                ThirdAuditEntity = new AggregateAuditEntity<StabilityAuditDto>
                {
                    NewEntities = mapper.Map<List<StabilityAuditDto>>(stablities),
                    PreEntities = preStablityList
                },
                OperateType = ActionTypeEnum.RegisterStart.Description(),
                Detail = string.Format(tips["StaticData.StartTestCondition"], entities.Select(e => e.ProductNo).Distinct().ToArray().Join())
            };
            await gxpAuditTrailService.Handle(InspAuditDto);

标签:审计,string,可读性,FreeSql,实体,AutoMapper,new,数据,追踪
来源: https://www.cnblogs.com/ankoo/p/16055533.html