查询过滤器

介绍

全局过滤器的作用是 设置 一个查询条件 ,当你使用查询操作的时候满足这个条件,那么你的语句就会附加你设置的条件

应用场景:过滤假删除数据 比如 每个查询后面都要加 isdelete=false

1、表过滤器 (推荐

 1.1 手动添加过滤器

根据实体添加过滤器,只要是这个实体的Queryable操作都会生效

/***过滤器写的位置***/
SqlSugarClient Db= new SqlSugarClient(new ConnectionConfig(){
           ConnectionString = "连接符字串", 
           DbType = DbType.SqlServer,
           IsAutoCloseConnection = true},
           db=>{
                  
               //过滤器写在这儿就行了
               db.QueryFilter.AddTableFilter<Order>(it => it.Name.Contains("a"));
               //如果是多租户
               //db.GetConnection(XXX).AddTableFilter 
               //用GetConnection还是GetConnectionScope和你代码要保持一致
           });
           
           
           
/***具体用例***/           

db.QueryFilter.AddTableFilter<Order>(it => it.Name.Contains("a"));
db.QueryFilter.AddTableFilterIF<Order>( isAdmin == false ,it => it.Name.Contains("a"));


//接口过滤器 (继承接口的类都有效) 请升级 5.1.3.47
db.QueryFilter.AddTableFilter<IDeleted>(it => it.IsDelete==false);

  
/****用例讲解***/
db.QueryFilter.AddTableFilter<Order>(it => it.Name.Contains("a"));//给Order类型加一个过滤器

//单表有效
db.Queryable<Order>().ToList();
// SELECT [Id],[Name],[Price],[CreateTime],[CustomId] FROM [Order]  WHERE  ([Name] like '%'+@MethodConst0+'%') 

//多表查询也有效
db.Queryable<OrderItem>().LeftJoin<Order>((i, o) => i.OrderId == o.Id)
        .Select((i,o)=>i).ToList();
//SELECT i.* FROM [OrderDetail] i Left Join [Order]  o  
//ON ( [i].[OrderId] = [o].[Id] )  AND  ([o].[Name] like '%'+@MethodConst1+'%')

 1.2 禁用、清空、备份和还原 

请升级5.1.3.47及以上版本

db.QueryFilter
.AddTableFilter<IDeletedFilter>(it => it.IsDeleted==false)//IDeletedFilter是自定义接口,继承这个接口的实体有效
.AddTableFilterIF<ITenantFilter>(isAdmint==false,it=>it.OrgId==用户OrgId);//ITenantFilter自定义接口

//用例1:单条语句清空,只影响当前语句
db.Queryable<Order>().ClearFilter().ToList();//所有过滤器都无效
db.Queryable<Order>().ClearFilter<IDeletedFilter>().ToList();//只有IDeletedFilter过滤器无效
db.Queryable<Order>().ClearFilter<IDeletedFilter,ITenantFilter>().ToList();//IDeletedFilter+ITenantFilter无效
  
//用例2:当前上下文清空 ,不会影响其他请求,只是当前请求清空
db.QueryFilter.Clear();
db.QueryFilter.Clear<IDeletedFilter>(); 

//用例3:清空并还原 ,不会影响其他请求,只是当前请求清空
db.QueryFilter.ClearAndBackup();//有多个重载 ClearAndBackup<T,T2>();
db.Queryable<Order>().ToList();
db.QueryFilter.Restore();//还原过滤器 (适合下面代码还需要过滤器情况)

 1.3 联表查询设置

//追加在on后面
db.QueryFilter.AddTableFilter<Order>(it=>it.Id==1)
//追加在where后面
db.QueryFilter.AddTableFilter<Order>(it=>it.Id==1,QueryFilterProvider.FilterJoinPosition.Where)

 1.4 动态添加 

 1.3.1 继承接口全局添加

//需要升级到 5.1.3.46-preview10 
db.QueryFilter.AddTableFilter<IDeleted>(it => it.IsDelete==false);
//符合条件执行过滤器
db.QueryFilter.AddTableFilterIF<IDeleted>(IsFilter==true ,it => it.IsDelete==false);

//实体类继承该接口就有效
public interface IDeleted
{
   public bool IsDelete{get;set;}
}

1.3.2 无接口动态添加

这种方式是应用第三方库进行字符串转表达式,能够处理相对复杂的逻辑

 Expression<Func<Order, bool>> dynamicExpression = it => it.Name=="b";//动态构造这种表达式
 Expression exp = dynamicExpression;
 Type type = typeof(Order);
 db.QueryFilter.AddTableFilter(type,exp);//新语法5.1.3.33
 //老语法
 // db.QueryFilter.Add(new TableFilterItem<object>(type, exp  ,true));
 db.Queryable<Order>().ToList();

具体实现:

//从程序集拿到实体type集合
Type[] types= Assembly
        .LoadFrom("XXX.dll")//如果 .dll报错,可以换成 xxx.exe 有些生成的是exe 
        .GetTypes().Where(it=>it.FullName.Contains("OrmTest."))//命名空间过滤,当然你也可以写其他条件过滤
         ToArray();//断点调试一下是不是需要的Type,不是需要的在进行过滤
// 遍历实体类
foreach(var entityType in types){
    if(!entityType.GetProperty("IsDeleted").IsEmpty()){ //判断实体类中包含IsDeleted属性
       //构建动态Lambda
      var lambda = DynamicExpressionParser.ParseLambda
      (new[] { Expression.Parameter(entityType, "it") },
       typeof(bool), $"{nameof(EntityBase.IsDeleted)} ==  @0",
        false);
      
      db.QueryFilter.AddTableFilter(entityType,lambda);//新语法5.1.3.33
      //老版本
      //db.QueryFilter.Add(new TableFilterItem<object>(entityType, lambda,true));//将Lambda传入过滤器
    }
    // 租户动态处理,同上
}
//DynamicExpressionParser 对象来自 System.Linq.Dynamic.Core


2、修改和删除用过滤器

查询是配置就生效,更新和删除要分自动和手动2种模式

2.1 局部设置

//删除
 db.Deleteable<Order>().EnableQueryFilter()//启用过滤器
 .Where(it => it.Id == 0)
 .ExecuteCommand();
 
//更新:只支持表达式方式更新 (如果实体方式更新建议先查询在更新)
  db.Updateable<Order>().EnableQueryFilter()//启用过滤器
  .SetColumns(it => it.Name == "a")
  .Where(it => it.Id == 1)
  .ExecuteCommand();

2.1 全局设置 (5.1.4.62)

 DbType = DbType.SqlServer,
 ConnectionString = Config.ConnectionString,
 IsAutoCloseConnection = true,
 MoreSettings=new ConnMoreSettings 
 { 
      IsAutoDeleteQueryFilter=true,//启用删除查询过滤器  
      IsAutoUpdateQueryFilter=true//启用更新查询过滤器 (表达式更新,如果是实体方式更新建议先查询在更新)
 }



3、子查询用过滤器

SqlFunc.Subqueryable<Order>().EnableTableFilter().Where(s=>s.id==it.xx).Any()


4、 不依赖实体过滤器

唯一优点不依赖实体,使用了过滤器所有 Queryable的 sql都会加上这一句

 //表单Queryable查询
 db2.QueryFilter.Add(new SqlFilterItem()
            {
                FilterValue = it =>
                {
                    //Writable logic
                    return new SqlFilterResult() { Sql = " name like '%a%' " };
                },
                IsJoinQuery = false // 单表生效  
            });
 //多表Queryable查询           
 db2.QueryFilter.Add(new SqlFilterItem()
            {
                FilterValue = it =>
                {
                    //Writable logic
                    return new SqlFilterResult() { Sql = " o.name like '%a%' " };
                },
                IsJoinQuery = true //多表生效
 });
 
 //可以用清空所有来清空


5、老版本写法

表过滤器老版本写法

//老版本
//db.QueryFilter.Add(new TableFilterItem<Order>(it => it.Name.Contains("a"),true))//true表示Leftjoin加on后面

//技巧:表过滤器使用Sql语句
//db.QueryFilter.AddTableFilter(it => SqlFunc.MappingColumn(default(bool),"id=1");

//清除过滤器
//db.Queryable<Order>().Filter(null,true).ToList();

6、相关功能

当前是介绍查询条件过滤,如果你想用AOP等功能可以看

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



文档:SqlSugar5.0