protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.Name == "Select") { if (node.Arguments[0].ToString().StartsWith(ProjectToParameterName)) //this is a Select created by Project.To(). { //Apply relevant filters. var newArg0 = ApplyFilters(node.Arguments[0]); //pass the second argument to a new query visitor to visit the remainder of the tree recursively & return the result QueryInjectorExpressionVisitor inner = new QueryInjectorExpressionVisitor(); inner._expressions = _expressions; inner._rootFilters = _rootFilters; inner._pathSoFar = _pathSoFar + node.Arguments[0].ToString().Replace(ProjectToParameterName, string.Empty) + "."; var newArg1 = inner.Visit(node.Arguments[1]); //Construct a new call to Select using the new args & return it return(Expression.Call(null, node.Method, newArg0, newArg1)); } } return(base.VisitMethodCall(node)); }
private void AddrelatedEntityFiltersIfApplicable <T>(Dictionary <Expression, Expression> relatedEntityFilters, Lictionary <Type, PropertyInfo> usingRelationships, ref IQueryable <T> query) { var filters = relatedEntityFilters.Clone(); var rootFilters = new Dictionary <Type, Expression>(); var props = this.GetType().GetProperties().Where(x => x.PropertyType.GetGenericTypeDefinition() == typeof(ISetAccessor) || typeof(ISetAccessor).IsAssignableFrom(x.PropertyType)); //group the properties by entity type, & exclude any type for which accessors are explicitly specified in a .Using() call var groupedProps = props.GroupBy(x => x.PropertyType.GetGenericArguments()[1]).Where(x => !usingRelationships.ContainsKey(x.Key)).ToDictionary(x => x.Key, x => x.Select(i => i).ToList()); //Add the filters specified in .Using() calls foreach (var key in usingRelationships.Keys) { if (usingRelationships[key].Count == 1) { var prop = usingRelationships[key].Single(); var setAccessor = prop.GetValue(this); var filter = (Expression)typeof(ISetAccessor).GetProperty("FilterExpression").GetValue(setAccessor); if (filter != null && filter.NodeType == ExpressionType.Lambda) { if ((filter as LambdaExpression).Body != (filter as LambdaExpression).Parameters[0]) { //filter expression actually does something so use it. var entityType = prop.PropertyType.GetGenericArguments()[1]; rootFilters.Add(entityType, filter); } } } else if (usingRelationships[key].Count > 1) { throw new CatFlapException("Only one .Using() can be specified per entity type per data retrieval operation. Multiple usings specified for: " + key.FullName); } else { throw new CatFlapException("usingRelationships collection cannot be empty"); } } foreach (var group in groupedProps) { PropertyInfo prop = null; if (group.Value.Count() == 1) { prop = group.Value.Single(); } else if (group.Value.Count() > 1) { var multiple = group.Value.Count(x => x.GetCustomAttributes <DefaultAttribute>().Count() == 1) > 1; if (multiple) { throw new CatFlapSetAccessorException("Ambiguous choice for relationship collection filter.\r\nMore than one SetAccessor<" + this.GetType().BaseType.GetGenericArguments()[0].FullName + "," + group.Key.FullName + "> property of " + this.GetType().FullName + " is decorated with the [RelationshipFilter] attribute."); } var none = group.Value.Count(x => x.GetCustomAttributes <DefaultAttribute>().Count() == 1) == 0; if (none) { throw new CatFlapSetAccessorException("Ambiguous choice for relationship collection filter.\r\nMore than one SetAccessor<" + this.GetType().BaseType.GetGenericArguments()[0].FullName + "," + group.Key.FullName + "> property exists on " + this.GetType().FullName + " but none is decorated with the [RelationshipFilter] attribute."); } prop = group.Value.Single(x => x.GetCustomAttributes <DefaultAttribute>().Count() == 1); } if (prop != null) { var setAccessor = prop.GetValue(this); var filter = (Expression)typeof(ISetAccessor).GetProperty("FilterExpression").GetValue(setAccessor); if (filter != null && filter.NodeType == ExpressionType.Lambda) { if ((filter as LambdaExpression).Body != (filter as LambdaExpression).Parameters[0]) { //filter expression actually does something so use it. var entityType = group.Key; rootFilters.Add(entityType, filter); } } } } if (filters.Count > 0 || rootFilters.Count > 0) { //inject the navigation property filters var resultingExpression = new QueryInjectorExpressionVisitor(filters, rootFilters).Visit((query as IQueryable).Expression); query = query.Provider.CreateQuery <T>(resultingExpression); } }