/// <summary>Sorts a query like a SQL ORDER BY clause does.</summary> /// <param name="source">Original source for query.</param> /// <param name="orderingInfo">Ordering definition to compose.</param> /// <returns>The composed query.</returns> internal static Expression OrderBy(Expression source, OrderingInfo orderingInfo) { Debug.Assert(source != null, "source != null"); Debug.Assert(orderingInfo != null, "orderingInfo != null"); Expression queryExpr = source; bool useOrderBy = true; foreach (OrderingExpression o in orderingInfo.OrderingExpressions) { LambdaExpression selectorLambda = (LambdaExpression)o.Expression; Type selectorType = selectorLambda.Body.Type; Debug.Assert(selectorType != null, "type != null"); // ensure either the expression type is orderable (ie, primitive) or its an open expression. if (!WebUtil.IsPrimitiveType(selectorType) && !OpenTypeMethods.IsOpenExpression(selectorLambda.Body)) { throw DataServiceException.CreateBadRequestError(Strings.RequestQueryParser_OrderByDoesNotSupportType(WebUtil.GetTypeName(selectorType))); } if (useOrderBy) { queryExpr = o.IsAscending ? queryExpr.QueryableOrderBy(selectorLambda) : queryExpr.QueryableOrderByDescending(selectorLambda); } else { queryExpr = o.IsAscending ? queryExpr.QueryableThenBy(selectorLambda) : queryExpr.QueryableThenByDescending(selectorLambda); } useOrderBy = false; } return(queryExpr); }
/// <summary>Finds the best methods for the specified arguments given a candidate method enumeration.</summary> /// <param name="methods">Enumerable object for candidate methods.</param> /// <param name="args">Argument expressions to match.</param> /// <param name="method">Best matched method.</param> /// <returns>The number of "best match" methods.</returns> private int FindBestMethod(IEnumerable <MethodBase> methods, Expression[] args, out MethodBase method) { MethodData[] applicable = this.FindApplicableMethods(methods, args); if (applicable.Length > 1) { applicable = FindBestApplicableMethods(applicable, args); } int result = applicable.Length; method = null; if (applicable.Length == 1) { // If we started off with all non-OpenType expressions and end with all-OpenType // expressions, we've been too aggresive - the transition from non-open-types // to open types should initially happen only as a result of accessing open properties. MethodData md = applicable[0]; bool originalArgsDefined = true; bool promotedArgsOpen = true; for (int i = 0; i < args.Length; i++) { originalArgsDefined = originalArgsDefined && !OpenTypeMethods.IsOpenPropertyExpression(args[i]); promotedArgsOpen = promotedArgsOpen && md.Parameters[i].ParameterType == typeof(object); args[i] = md.Args[i]; } method = (originalArgsDefined && promotedArgsOpen) ? null : md.MethodBase; result = (method == null) ? 0 : 1; } else if (applicable.Length > 1) { // We may have the case for operators (which C# doesn't) in which we have a nullable operand // and a non-nullable operand. We choose to convert the one non-null operand to nullable in that // case (the binary expression will lift to null). if (args.Length == 2 && applicable.Length == 2 && WebUtil.GetNonNullableType(applicable[0].Parameters[0].ParameterType) == WebUtil.GetNonNullableType(applicable[1].Parameters[0].ParameterType)) { MethodData nullableMethod = WebUtil.TypeAllowsNull(applicable[0].Parameters[0].ParameterType) ? applicable[0] : applicable[1]; args[0] = nullableMethod.Args[0]; args[1] = nullableMethod.Args[1]; return(this.FindBestMethod(methods, args, out method)); } } return(result); }
public void OpenCollectionTranslatorShouldConvertAllWithBody() { this.TestLambda <AllNode, Customer, bool>(this.OpenCollectionNavigationFromParameter("o", "OpenOtherCustomers"), "i", Constant(false), o => OpenTypeMethods.GetCollectionValue(o, "OpenOtherCustomers").All(i => false)); }
public void TranslatorShouldConvertOpenCollectionProperty() { this.TestOpenCollectionProperty <Customer, object>(EntityParameter <Customer>("c"), "Foo", c => OpenTypeMethods.GetCollectionValue(c, "Foo")); }