private void TranslateThenBy(MethodCallExpression methodCallExpression) { if (methodCallExpression.Arguments.Count != 2) { throw new ArgumentOutOfRangeException("methodCallExpression"); } if (_orderBy == null) { throw new NotSupportedException("ThenBy or ThenByDescending can only be used after OrderBy or OrderByDescending."); } var key = (LambdaExpression)StripQuote(methodCallExpression.Arguments[1]); var direction = (methodCallExpression.Method.Name == "ThenByDescending") ? OrderByDirection.Descending : OrderByDirection.Ascending; var clause = new OrderByClause(key, direction); _orderBy.Add(clause); }
private void TranslateOrderBy(MethodCallExpression methodCallExpression) { if (methodCallExpression.Arguments.Count != 2) { throw new ArgumentOutOfRangeException("methodCallExpression"); } if (_orderBy != null) { throw new NotSupportedException("Only one OrderBy or OrderByDescending clause is allowed (use ThenBy or ThenByDescending for multiple order by clauses)."); } var key = (LambdaExpression)StripQuote(methodCallExpression.Arguments[1]); var direction = (methodCallExpression.Method.Name == "OrderByDescending") ? OrderByDirection.Descending : OrderByDirection.Ascending; var clause = new OrderByClause(key, direction); _orderBy = new List<OrderByClause>(); _orderBy.Add(clause); }
private void TranslateMaxMin(MethodCallExpression methodCallExpression) { var methodName = methodCallExpression.Method.Name; if (_orderBy != null) { var message = string.Format("{0} cannot be used with OrderBy.", methodName); throw new NotSupportedException(message); } if (_skip != null || _take != null) { var message = string.Format("{0} cannot be used with Skip or Take.", methodName); throw new NotSupportedException(message); } switch (methodCallExpression.Arguments.Count) { case 1: break; case 2: if (_projection != null) { var message = string.Format("{0} must be used with either Select or a selector argument, but not both.", methodName); throw new NotSupportedException(message); } _projection = (LambdaExpression)StripQuote(methodCallExpression.Arguments[1]); break; default: throw new ArgumentOutOfRangeException("methodCallExpression"); } if (_projection == null) { var message = string.Format("{0} must be used with either Select or a selector argument.", methodName); throw new NotSupportedException(message); } // implement Max/Min by sorting on the relevant field(s) and taking the first result _orderBy = new List<OrderByClause>(); if (_projection.Body.NodeType == ExpressionType.New) { // take the individual constructor arguments and make new lambdas out of them for the OrderByClauses var newExpression = (NewExpression)_projection.Body; foreach (var keyExpression in newExpression.Arguments) { var delegateTypeGenericDefinition = typeof(Func<,>); var delegateType = delegateTypeGenericDefinition.MakeGenericType(_projection.Parameters[0].Type, keyExpression.Type); var keyLambda = Expression.Lambda(delegateType, keyExpression, _projection.Parameters); var clause = new OrderByClause(keyLambda, (methodName == "Min") ? OrderByDirection.Ascending : OrderByDirection.Descending); _orderBy.Add(clause); } } else { var clause = new OrderByClause(_projection, (methodName == "Min") ? OrderByDirection.Ascending : OrderByDirection.Descending); _orderBy.Add(clause); } _take = Expression.Constant(1); SetElementSelector(methodCallExpression, source => source.Cast<object>().First()); }
private void TranslateLast(MethodCallExpression methodCallExpression) { LambdaExpression predicate = null; switch (methodCallExpression.Arguments.Count) { case 1: break; case 2: predicate = (LambdaExpression)StripQuote(methodCallExpression.Arguments[1]); break; default: throw new ArgumentOutOfRangeException("methodCallExpression"); } CombinePredicateWithWhereClause(methodCallExpression, predicate); // when using OrderBy without Take Last can be much faster by reversing the sort order and using First instead of Last if (_orderBy != null && _take == null) { for (int i = 0; i < _orderBy.Count; i++) { var clause = _orderBy[i]; var oppositeDirection = (clause.Direction == OrderByDirection.Descending) ? OrderByDirection.Ascending : OrderByDirection.Descending; _orderBy[i] = new OrderByClause(clause.Key, oppositeDirection); } _take = Expression.Constant(1); switch (methodCallExpression.Method.Name) { case "Last": SetElementSelector(methodCallExpression, source => source.Cast<object>().First()); break; case "LastOrDefault": SetElementSelector(methodCallExpression, source => source.Cast<object>().FirstOrDefault()); break; } } else { switch (methodCallExpression.Method.Name) { case "Last": SetElementSelector(methodCallExpression, source => source.Cast<object>().Last()); break; case "LastOrDefault": SetElementSelector(methodCallExpression, source => source.Cast<object>().LastOrDefault()); break; } } }
private void TranslateMaxMin(MethodCallExpression methodCallExpression) { var methodName = methodCallExpression.Method.Name; if (_orderBy != null) { var message = string.Format("{0} cannot be used with OrderBy.", methodName); throw new NotSupportedException(message); } if (_skip != null || _take != null) { var message = string.Format("{0} cannot be used with Skip or Take.", methodName); throw new NotSupportedException(message); } switch (methodCallExpression.Arguments.Count) { case 1: break; case 2: if (_projection != null) { var message = string.Format("{0} must be used with either Select or a selector argument, but not both.", methodName); throw new NotSupportedException(message); } _projection = (LambdaExpression)StripQuote(methodCallExpression.Arguments[1]); break; default: throw new ArgumentOutOfRangeException("methodCallExpression"); } if (_projection == null) { var message = string.Format("{0} must be used with either Select or a selector argument.", methodName); throw new NotSupportedException(message); } // implement Max/Min by sorting on the relevant field(s) and taking the first result _orderBy = new List <OrderByClause>(); if (_projection.Body.NodeType == ExpressionType.New) { // take the individual constructor arguments and make new lambdas out of them for the OrderByClauses var newExpression = (NewExpression)_projection.Body; foreach (var keyExpression in newExpression.Arguments) { var delegateTypeGenericDefinition = typeof(Func <,>); var delegateType = delegateTypeGenericDefinition.MakeGenericType(_projection.Parameters[0].Type, keyExpression.Type); var keyLambda = Expression.Lambda(delegateType, keyExpression, _projection.Parameters); var clause = new OrderByClause(keyLambda, (methodName == "Min") ? OrderByDirection.Ascending : OrderByDirection.Descending); _orderBy.Add(clause); } } else { var clause = new OrderByClause(_projection, (methodName == "Min") ? OrderByDirection.Ascending : OrderByDirection.Descending); _orderBy.Add(clause); } _take = 1; SetElementSelector(methodCallExpression, source => source.Cast <object>().First()); }
private void TranslateLast(MethodCallExpression methodCallExpression) { if (methodCallExpression.Arguments.Count != 1) { throw new ArgumentOutOfRangeException("methodCallExpression"); } if (_elementSelector != null) { var message = string.Format("{0} cannot be combined with any other element selector.", methodCallExpression.Method.Name); throw new InvalidOperationException(message); } // when using OrderBy without Take Last can be much faster by reversing the sort order and using First instead of Last if (_orderBy != null && _take == null) { for (int i = 0; i < _orderBy.Count; i++) { var clause = _orderBy[i]; var oppositeDirection = (clause.Direction == OrderByDirection.Descending) ? OrderByDirection.Ascending : OrderByDirection.Descending; _orderBy[i] = new OrderByClause(clause.Key, oppositeDirection); } _take = Expression.Constant(1); switch (methodCallExpression.Method.Name) { case "Last": _elementSelector = (IEnumerable source) => source.Cast<object>().First(); break; case "LastOrDefault": _elementSelector = (IEnumerable source) => source.Cast<object>().FirstOrDefault(); break; } } else { switch (methodCallExpression.Method.Name) { case "Last": _elementSelector = (IEnumerable source) => source.Cast<object>().Last(); break; case "LastOrDefault": _elementSelector = (IEnumerable source) => source.Cast<object>().LastOrDefault(); break; } } }