标签:审计 string 可读性 FreeSql 实体 AutoMapper new 数据 追踪
基础概念
系统内对数据的操作通过数据库实体保存到库,通过数据库实体我们可以获取到变化之前的数据和变化之后的数据,但是基于数据库实体记录审计追踪有很大的弊病。
数据库实体的结构是基于业务需要设计的,一般很难满足审计追踪的观赏性方面的需求,要么是多出很多用户看不懂的字段,如主键、版本号等;要么是缺少必要的解释字段,比如有用户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);
使用这种方式有一些限制条件:
- 方法需要有【Transaction】属性,整个方法处在事务中
- 变化的实体数据已经被FreeSql追踪,如果使用了UpdateDiy、ToUpdate等不会追踪变化的FreeSql功能,将无法正确获取变化前后的实体数据
- 数据库实体一定要通过AutoMapper映射到对应的AuditDto
- 实体中包含所需要记录的全部数据。例,如果实体中有用户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
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。