protected override Expression VisitMethodCall(MethodCallExpression expression) { if (invariantExpression) { return(base.VisitMethodCall(expression)); } bool sameQueryable = expression.Method.DeclaringType == typeof(Queryable) && ContainsOrEquals(expression.Arguments[0], parameters[0]); if (builder.SelectExpression != null && !sameQueryable) { return(base.VisitMethodCall(expression)); } SPModelQueryExpressionScope currentScope = this.currentScope; try { SPModelQueryExpressionScope childScope = new SPModelQueryExpressionScope(this); this.currentScope = childScope; if (sameQueryable) { ValidateQueryableMethodCall(expression); ParameterExpression currentLambdaParam = lambdaParam; Visit(expression.Arguments[0]); currentScope.Expression = childScope.Expression; childScope.Reset(); currentScope.Expression += GetExpressionFromQueryableMethod(expression); lambdaParam = currentLambdaParam; return(expression); } if (expression.Method.DeclaringType == typeof(Enumerable) || expression.Method.DeclaringType.IsOf(typeof(ICollection <>))) { currentScope.Expression = GetExpressionFromEnumerableMethod(expression); return(expression); } if (expression.Method.DeclaringType == typeof(string)) { currentScope.Expression = GetExpressionFromStringMethod(expression); return(expression); } if (expression.Method.Name == "Equals" && expression.Arguments.Count == 1) { Visit(expression.Object); Visit(expression.Arguments[0]); currentScope.Expression = childScope.GetExpression((SPModelQueryExpressionScope.ExpressionGenerator)Caml.Equals); return(expression); } throw ThrowMethodNotSupported(expression.Method); } finally { this.currentScope = currentScope; } }
protected override Expression VisitBinary(BinaryExpression expression) { SPModelQueryExpressionScope currentScope = stack.Peek(); SPModelQueryExpressionScope childScope = new SPModelQueryExpressionScope(this); SPModelQueryExpressionScope childScopeTwo = null; stack.Push(childScope); Visit(expression.Left); if (expression.NodeType == ExpressionType.AndAlso || expression.NodeType == ExpressionType.OrElse) { stack.Pop(); childScopeTwo = new SPModelQueryExpressionScope(this); stack.Push(childScopeTwo); } Visit(expression.Right); switch (expression.NodeType) { case ExpressionType.AndAlso: currentScope.Expression = childScope.Expression & childScopeTwo.Expression; break; case ExpressionType.OrElse: currentScope.Expression = childScope.Expression | childScopeTwo.Expression; break; case ExpressionType.Equal: if (childScope.Value == null) { currentScope.Expression = childScope.GetExpression(s => HandleNullExpression(s, false)); } else { currentScope.Expression = childScope.GetExpression((SPModelQueryExpressionScope.ExpressionGenerator)Caml.Equals); } break; case ExpressionType.NotEqual: if (childScope.Value == null) { currentScope.Expression = childScope.GetExpression(s => HandleNullExpression(s, true)); } else { currentScope.Expression = childScope.GetExpression(Caml.NotEquals); } break; case ExpressionType.LessThan: currentScope.Expression = childScope.GetExpression(Caml.LessThan); break; case ExpressionType.LessThanOrEqual: currentScope.Expression = childScope.GetExpression(Caml.LessThanOrEqual); break; case ExpressionType.GreaterThan: currentScope.Expression = childScope.GetExpression(Caml.GreaterThan); break; case ExpressionType.GreaterThanOrEqual: currentScope.Expression = childScope.GetExpression(Caml.GreaterThanOrEqual); break; default: throw new NotSupportedException(String.Format("The binary operator '{0}' is not supported", expression.NodeType)); } stack.Pop(); return(expression); }
protected override Expression VisitMethodCall(MethodCallExpression expression) { SPModelQueryExpressionScope currentScope = stack.Peek(); SPModelQueryExpressionScope childScope = new SPModelQueryExpressionScope(this); stack.Push(childScope); if (expression.Method.DeclaringType == typeof(Queryable)) { Visit(expression.Arguments[0]); currentScope.Expression = childScope.Expression; childScope.Reset(); switch (expression.Method.Name) { case "Where": if (expression.Arguments.Count == 3) { throw new NotSupportedException(String.Format("The method '{0}' with element's index used in the logic is not supported", expression.Method.Name)); } Visit(expression.Arguments[1]); currentScope.Expression += childScope.Expression; break; case "Union": if (expression.Arguments.Count == 3) { throw new NotSupportedException(String.Format("The method '{0}' with element's index used in the logic is not supported", expression.Method.Name)); } Visit(expression.Arguments[1]); currentScope.Expression |= childScope.Expression; break; case "Count": result.ExecuteMode = Enum <SPModelQueryExecuteMode> .Parse(expression.Method.Name); if (expression.Arguments.Count > 1) { Visit(expression.Arguments[1]); currentScope.Expression += childScope.Expression; } break; case "All": case "Any": case "FirstOrDefault": case "First": case "SingleOrDefault": case "Single": case "ElementAtOrDefault": case "ElementAt": result.ExecuteMode = Enum <SPModelQueryExecuteMode> .Parse(expression.Method.Name); if (result.ExecuteMode == SPModelQueryExecuteMode.ElementAt || result.ExecuteMode == SPModelQueryExecuteMode.ElementAtOrDefault) { result.Limit += Math.Max(0, Convert.ToInt32(((ConstantExpression)expression.Arguments[1]).Value)); } else if (result.ExecuteMode == SPModelQueryExecuteMode.Single || result.ExecuteMode == SPModelQueryExecuteMode.SingleOrDefault) { result.Limit = 2; } else { result.Limit = 1; } if (expression.Arguments.Count > 1) { Visit(expression.Arguments[1]); currentScope.Expression += childScope.Expression; } break; case "Take": result.Limit = Math.Max(0, Convert.ToInt32(((ConstantExpression)expression.Arguments[1]).Value)); break; case "Skip": result.Offset = Math.Max(0, Convert.ToInt32(((ConstantExpression)expression.Arguments[1]).Value)); break; case "OrderBy": case "ThenBy": if (expression.Arguments.Count == 3) { throw new NotSupportedException(String.Format("The method '{0}' with specified comparer is not supported", expression.Method.Name)); } Visit(expression.Arguments[1]); currentScope.Expression += childScope.GetExpression(s => Caml.OrderByAscending(s.FieldRef), true); break; case "OrderByDescending": case "ThenByDescending": if (expression.Arguments.Count == 3) { throw new NotSupportedException(String.Format("The method '{0}' with specified comparer is not supported", expression.Method.Name)); } Visit(expression.Arguments[1]); currentScope.Expression += childScope.GetExpression(s => Caml.OrderByDescending(s.FieldRef), true); break; case "Select": result.SelectExpression = (LambdaExpression)StripQuotes(expression.Arguments[1]); break; case "OfType": result.ModelType = expression.Method.GetGenericArguments()[0]; break; default: throw new NotSupportedException(String.Format("The method '{0}' is not supported", expression.Method.Name)); } } else if (expression.Method.DeclaringType == typeof(Enumerable)) { switch (expression.Method.Name) { case "Contains": if (expression.Arguments.Count == 3) { throw new NotSupportedException(String.Format("The method '{0}' with specified comparer is not supported", expression.Method.Name)); } Visit(expression.Arguments[0]); Visit(expression.Arguments[1]); if (childScope.Value is IEnumerable) { if (((IEnumerable)childScope.Value).OfType <object>().Any()) { currentScope.Expression = childScope.GetExpression(Caml.EqualsAny); } else { currentScope.Expression = CamlExpression.False; } } else { currentScope.Expression = childScope.GetExpression(Caml.Includes); } break; default: throw new NotSupportedException(String.Format("The method '{0}' is not supported", expression.Method.Name)); } } else if (expression.Method.DeclaringType == typeof(String)) { Visit(expression.Object); switch (expression.Method.Name) { case "StartsWith": Visit(expression.Arguments[0]); currentScope.Expression = childScope.GetExpression(s => Caml.BeginsWith(s.FieldRef, (childScope.Value ?? String.Empty).ToString())); break; default: throw new NotSupportedException(String.Format("The method '{0}' is not supported", expression.Method.Name)); } } else if (expression.Method.DeclaringType.IsOf(typeof(ICollection <>))) { switch (expression.Method.Name) { case "Contains": Visit(expression.Object); Visit(expression.Arguments[0]); if (childScope.Value is IEnumerable) { if (((IEnumerable)childScope.Value).OfType <object>().Any()) { currentScope.Expression = childScope.GetExpression(Caml.EqualsAny); } else { currentScope.Expression = CamlExpression.False; } } else { currentScope.Expression = childScope.GetExpression(Caml.Includes); } break; default: throw new NotSupportedException(String.Format("The method '{0}' is not supported", expression.Method.Name)); } } else if (expression.Method.Name == "Equals" && expression.Arguments.Count == 1) { Visit(expression.Object); Visit(expression.Arguments[0]); currentScope.Expression = childScope.GetExpression((SPModelQueryExpressionScope.ExpressionGenerator)Caml.Equals); } else { throw new NotSupportedException(String.Format("The method '{0}' is not supported", expression.Method.Name)); } stack.Pop(); return(expression); }
protected override Expression VisitMemberAccess(MemberExpression expression) { if (invariantExpression) { return(base.VisitMemberAccess(expression)); } if (expression.Expression != lambdaParam) { if (expression.Member.DeclaringType == typeof(ISPModelMetaData) && ((expression.Expression.NodeType == ExpressionType.Call && ((MethodCallExpression)expression.Expression).Method == typeof(SPModelExtension).GetMethod("GetMetaData") && ((MethodCallExpression)expression.Expression).Arguments[0] == lambdaParam) || (expression.Expression.NodeType == ExpressionType.Convert && ((UnaryExpression)expression.Expression).Operand == lambdaParam))) { // allow non-direct field access on the ISPModelMetaData interface } else { Expression result = base.VisitMemberAccess(expression); if (expression.Member.DeclaringType.IsGenericType && expression.Member.DeclaringType.GetGenericTypeDefinition() == typeof(Nullable <>) && expression.Member.Name == "HasValue") { CamlExpression expr = currentScope.GetExpression(v => Caml.IsNotNull(v.FieldRef)); currentScope.Reset(); currentScope.Expression = expr; } return(result); } } currentScope.MemberType = expression.Type; currentScope.Member = expression.Member; currentScope.Field = default(SPModelQueryFieldInfo); currentScope.FieldAssociations = null; if (expression.Member.DeclaringType == typeof(ISPModelMetaData)) { switch (expression.Member.Name) { case "ID": currentScope.Field = SPModelQueryFieldInfo.ID; break; case "UniqueId": currentScope.Field = SPModelQueryFieldInfo.UniqueId; break; case "FileRef": currentScope.Field = SPModelQueryFieldInfo.FileRef; break; case "FileLeafRef": currentScope.Field = SPModelQueryFieldInfo.FileLeafRef; break; case "LastModified": currentScope.Field = SPModelQueryFieldInfo.LastModified; break; case "CheckOutUserID": currentScope.Field = SPModelQueryFieldInfo.CheckOutUserID; break; default: throw new NotSupportedException(String.Format("Member '{0}' is not supported", GetMemberFullName(expression.Member))); } } else { currentScope.FieldAssociations = SPModelFieldAssociationCollection.GetByMember(expression.Member); foreach (SPFieldAttribute field in currentScope.FieldAssociations.Fields) { if (field.TypeAsString == "TaxonomyFieldType" || field.TypeAsString == "TaxonomyFieldTypeMulti") { builder.TaxonomyFields.Add(field.ListFieldInternalName); } } } if (builder.SelectExpression != null) { if (currentScope.Field.FieldRef != null) { builder.AddSelectProperty(currentScope.Field.FieldRef); } else if (currentScope.FieldAssociations.Queryable && expression.Member.MemberType == MemberTypes.Property && ((PropertyInfo)expression.Member).GetGetMethod().IsAbstract) { builder.AddSelectProperty(currentScope.FieldAssociations.Fields.First().ListFieldInternalName); } else { builder.SelectAllProperties = true; } } return(expression); }
protected override Expression VisitBinary(BinaryExpression expression) { if (invariantExpression || builder.SelectExpression != null) { return(base.VisitBinary(expression)); } SPModelQueryExpressionScope currentScope = this.currentScope; SPModelQueryExpressionScope childScope = new SPModelQueryExpressionScope(this); SPModelQueryExpressionScope childScopeTwo = null; this.currentScope = childScope; if (expression.NodeType == ExpressionType.AndAlso || expression.NodeType == ExpressionType.OrElse) { childScopeTwo = new SPModelQueryExpressionScope(this); VisitConditionalBranch(expression.Left); this.currentScope = childScopeTwo; VisitConditionalBranch(expression.Right); } else { Visit(expression.Left); Visit(expression.Right); } switch (expression.NodeType) { case ExpressionType.AndAlso: currentScope.Expression = childScope.Expression & childScopeTwo.Expression; break; case ExpressionType.OrElse: currentScope.Expression = childScope.Expression | childScopeTwo.Expression; break; case ExpressionType.Equal: currentScope.Expression = childScope.GetExpression(s => HandleEqualityComparison(s, CamlBinaryOperator.Eq)); break; case ExpressionType.NotEqual: currentScope.Expression = childScope.GetExpression(s => HandleEqualityComparison(s, CamlBinaryOperator.Neq)); break; case ExpressionType.LessThan: currentScope.Expression = childScope.GetExpression(Caml.LessThan); break; case ExpressionType.LessThanOrEqual: currentScope.Expression = childScope.GetExpression(Caml.LessThanOrEqual); break; case ExpressionType.GreaterThan: currentScope.Expression = childScope.GetExpression(Caml.GreaterThan); break; case ExpressionType.GreaterThanOrEqual: currentScope.Expression = childScope.GetExpression(Caml.GreaterThanOrEqual); break; default: throw new NotSupportedException(String.Format("Binary operator '{0}' is not supported", expression.NodeType)); } this.currentScope = currentScope; return(expression); }