AOP、日志、拦截

1、SQL事件

注意:Aop一定要设置在你操作语句之前,不然不会生效,还有必须是同一个SqlSuagrClient才会有效

public  SqlSugarClient GetInstance()
{
    SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
        {
            ConnectionString = "Server=.xxxxx",
            DbType = DbType.SqlServer,
            IsAutoCloseConnection = true,
            InitKeyType = InitKeyType.Attribute
        });
    //每次Sql执行前事件
    db.Aop.OnLogExecuting = (sql, pars) =>
    {
         //我可以在这里面写逻辑
    };
    return db;
}
var db=GetInstance();
db.Queryable<T>().ToList();//执行操作会进事件

全部事件

//SQL执行完
db.Aop.OnLogExecuted = (sql, pars) => 
{
 //执行完了可以输出SQL执行时间 (OnLogExecutedDelegate) 
 Console.Write("time:" + db.Ado.SqlExecutionTime.ToString()); 
};
db.Aop.OnLogExecuting = (sql, pars) => //SQL执行前
{
    //5.0.8.2 获取无参数化 SQL 
     //UtilMethods.GetSqlString(DbType.SqlServer,sql,pars)
};
db.Aop.OnError = (exp) =>//SQL报错
{
    //exp.sql 这样可以拿到错误SQL,性能无影响拿到ORM带参数使用的SQL
    
     //5.0.8.2 获取无参数化 SQL  对性能有影响,特别大的SQL参数多的,调试使用
     //UtilMethods.GetSqlString(DbType.SqlServer,exp.sql,exp.parameters)           
};
db.Aop.OnExecutingChangeSql = (sql, pars) => //可以修改SQL和参数的值
{
    //sql=newsql
    //foreach(var p in pars) //修改
    return new KeyValuePair<string, SugarParameter[]>(sql,pars);
};


2、数据事件  (插入更新)

数据过滤器

(2.1) 插入和更新过滤器

插入或者更新可以修改 实体里面的值,比如插入或者更新 赋默认值 (审计)

   db.Aop.DataExecuting = (oldValue, entityInfo) =>
   {
      /*** inset生效 ***/
      if (entityInfo.PropertyName == "CreateTime"&&entityInfo.OperationType== DataFilterType.InsertByObject)
      {
         entityInfo.SetValue(DateTime.Now);//修改CreateTime字段
         //entityInfo有字段所有参数
         
         // oldValue表示当前字段值 等同于下面写法
         // var value=entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue);
      }
      //特性用法
      //if(p.EntityColumnInfo.PropertyInfo.GetCustomAttribute<自定义特性>()!=null
      // &&entityInfo.OperationType== DataFilterType.InsertByObject)
      //5.1.3.23 更好的支持了特性
      //p.IsAnyAttribute<特性>()
      //p.GetAttribute<特性>()
      
      
      /*** update生效 ***/       
      if (entityInfo.PropertyName =="UpdateTime" && entityInfo.OperationType == DataFilterType.UpdateByObject)
      {
         entityInfo.SetValue(DateTime.Now);//修改UpdateTime字段
      }
      
      //根据当前列修改另一列 可以么写
      //if(当前列逻辑==XXX)
      //var properyDate = entityInfo.EntityValue.GetType().GetProperty("Date");
       //if(properyDate!=null)
      //properyDate.SetValue(entityInfo.EntityValue,1);
   };
 
  /***实体插入都支持***/
  db.Insertable(data).ExecuteReturnIdentity();
  
  /***实体方式更新***/
  db.Updateable(data).ExecuteCommand(); 
  db.Updateable(insertObj).IgnoreColumns(ignoreAllNullColumns:true).ExecuteCommand();  
  
  /***表达式方式更新***/
  //新功能 5.1.3.2:表达式更新支持数据过滤器   
  db.Updateable<Order>()
      .SetColumns(it => new Order(){Name="A"}
      ,appendColumnsByDataFilter:true)//true表式追加过滤器赋值字段
      .Where(it=>it.Id==1).ToSqlString()
  
  //兼容其它ORM AOP写法
  //SqlSugar是通过每行记录每个值进行的细粒度AOP,如果一行数据只想进一次事件
   if (entityInfo.EntityColumnInfo.IsPrimarykey) //通过主键保证只进一次事件
    {
      //这样每条记录就只执行一次 
    }

(2.2) 查询数据转换 

新功能:5.1.2-preview05

    db.Aop.DataExecuted = (value, entity) =>
    {
        if (entity.Entity.Type == typeof(Order)) 
        {
            var newValue=entity.GetValue(nameof(Order.Name))+"111";
            entity.SetValue(nameof(Order.Name), newValue);
        }
    };
    //查询出来的值的 name都加上了 111
    List<Order> list2 = db.Queryable<Order>().ToList();

(2.3) 加密和解密

2.1和2.2一起用就可以实现加密和解密字段

(2.4) 查询过滤器

https://www.donet5.com/Home/Doc?typeId=1205


3、差异日志功能

注意: 5.0.4.4 支持批量操作

Sql执行完后会进该事件,该事件可以拿到更改前记录和更改后记录,执行时间等参数(可以监控表变动)

该功能和 EF Core ChangeTracker 类似

db.Aop.OnDiffLogEvent = it =>
{
                //操作前记录  包含: 字段描述 列名 值 表名 表描述
                var editBeforeData = it.BeforeData;//插入Before为null,之前还没进库
                //操作后记录   包含: 字段描述 列名 值  表名 表描述
                var editAfterData = it.AfterData;
                var sql = it.Sql;
                var parameter = it.Parameters;
                var data = it.BusinessData;//这边会显示你传进来的对象
                var time = it.Time;
                var  diffType=it.DiffType;//enum insert 、update and delete  
                 
                //Write logic
};
 
 
db.Insertable(new Student() { Name = "beforeName" })
.EnableDiffLogEvent() //注意需要加上启用日志
.ExecuteReturnIdentity();
 
db.Updateable<Student>(new Student()
            {
                Id = id,
                CreateTime = DateTime.Now,
                Name = "afterName",
                SchoolId = 2
            })
.EnableDiffLogEvent(new { title = "update Student", Modular = 1, Operator = "admin" }) //启用并传业务对象参数
.ExecuteCommand();
 
db.Deleteable<Student>(id)
.EnableDiffLogEvent("删除学生") //启用传字符串业务参数
.ExecuteCommand();


4、实体特性实现AOP

这么改你所有操生成的sql表名前面就加了前缀  select * from "public"."表名"

 return new SqlSugarClient(new ConnectionConfig()
            {
                DbType = SqlSugar.DbType.PostgreSQL,
                ConnectionString = Config.ConnectionString,
                InitKeyType = InitKeyType.Attribute,
                IsAutoCloseConnection = true,
                ConfigureExternalServices=new ConfigureExternalServices() {
                    EntityNameService = (type, entity) => 
                    {
                        entity.DbTableName = "public." + entity.DbTableName;
                    }
                }
            });

上面只修改了表,如果我要表和列都修改呢

EntityNameService = (type, entity) => 
{
  //修改表        
},
EntityService = (type, column) => 
{
   //修改列
}


5、监控所有超过1秒的Sql

   SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
   {
                DbType = DbType.SqlServer,
                ConnectionString = Config.ConnectionString,
                InitKeyType = InitKeyType.Attribute,
                IsAutoCloseConnection = true
              
   });
    db.Aop.OnLogExecuted = (sql, p) =>
    {
         //执行时间超过1秒
        if (db.Ado.SqlExecutionTime.TotalSeconds > 1) 
        {
            //代码CS文件名
            var fileName= db.Ado.SqlStackTrace.FirstFileName;
            //代码行数
            var fileLine = db.Ado.SqlStackTrace.FirstLine;
            //方法名
            var FirstMethodName = db.Ado.SqlStackTrace.FirstMethodName;
            //db.Ado.SqlStackTrace.MyStackTraceList[1].xxx 获取上层方法的信息
         }
         //相当于EF的 PrintToMiniProfiler
   };


6、多租户AOP设置

查看第4条 多租户-SqlSugar 5x-文档园 (donet5.com)


7、中间管道

这个功能相当于替换ADO执行方法,已经超出来AOP的范畴

https://www.donet5.com/Home/Doc?typeId=2413


8、查询过滤器

https://www.donet5.com/home/Doc?typeId=1205

文档:SqlSugar5.0