IBuildContext ApplyQueryFilters(ExpressionBuilder builder, BuildInfo buildInfo, MemberInfo?memberInfo, TableContext tableContext) { var entityType = tableContext.ObjectType; if (builder.IsFilterDisabled(entityType)) { return(tableContext); } var ed = builder.MappingSchema.GetEntityDescriptor(entityType); var filterFunc = ed.QueryFilterFunc; if (filterFunc == null) { return(tableContext); } if (memberInfo == null) { memberInfo = Methods.LinqToDB.GetTable.MakeGenericMethod(entityType); } var fakeQuery = ExpressionQueryImpl.CreateQuery(entityType, builder.DataContext, null); // Here we tell for Equality Comparer to compare optimized expressions // builder.AddQueryableMemberAccessors(new AccessorMember(memberInfo), builder.DataContext, (mi, dc) => { var filtered = (IQueryable)filterFunc.DynamicInvoke(fakeQuery, dc) !; // here we use light version of optimization, only for comparing trees var optimizationContext = new ExpressionTreeOptimizationContext(dc); var optimizedExpr = ExpressionBuilder.CorrectDataConnectionReference(filtered.Expression, ExpressionBuilder.DataContextParam); optimizedExpr = optimizationContext.ExposeExpression(optimizedExpr); optimizedExpr = optimizationContext.ExpandQueryableMethods(optimizedExpr); return(optimizedExpr); }); var filtered = (IQueryable)filterFunc.DynamicInvoke(fakeQuery, builder.DataContext) !; var optimized = ExpressionBuilder.CorrectDataConnectionReference(filtered.Expression, ExpressionBuilder.DataContextParam); optimized = builder.ConvertExpressionTree(optimized); optimized = builder.ConvertExpression(optimized); var refExpression = new ContextRefExpression(typeof(IQueryable <>).MakeGenericType(entityType), tableContext); var replaced = optimized.Replace(fakeQuery.Expression, refExpression); if (replaced == optimized) { throw new LinqException("Could not correct query result for processing."); } var context = builder.BuildSequence(new BuildInfo(buildInfo, replaced)); return(context); }