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((filterFunc, fakeQuery), new AccessorMember(memberInfo), builder.DataContext, static (context, mi, dc) =>
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 // var closureMappingSchema = builder.MappingSchema; builder.AddQueryableMemberAccessors(memberInfo, mi => { var filtered = (IQueryable)filterFunc.DynamicInvoke(fakeQuery, builder.DataContext); // here we use light version of optimization, only for comparing trees var optimizationContext = new ExpressionTreeOptimizationContext(closureMappingSchema); var optimizedExpr = optimizationContext.ExposeExpression(filtered.Expression); optimizedExpr = optimizationContext.ExpandQueryableMethods(optimizedExpr); optimizedExpr = optimizedExpr.OptimizeExpression() !; return(optimizedExpr); }); var filtered = (IQueryable)filterFunc.DynamicInvoke(fakeQuery, builder.DataContext); var optimized = filtered.Expression; optimized = builder.ConvertExpressionTree(optimized); optimized = builder.ConvertExpression(optimized); optimized = optimized.OptimizeExpression() !; 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); }