Beispiel #1
0
        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));
        }
Beispiel #2
0
        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);
            }
        }