private ODataExpression TranslateInternal(Expression linq) { if (linq == null) { return(null); } // captured parameters object value; if (TryGetValueFast(linq, out value)) { // special case the handling of queryable constants, since these can be the "root" // of the query expression tree. We check for isInsideQuery since we don't allow multiple // roots. An example of a multiply-rooted tree would be: q.Where(x => q.Any(xx => xx.A < x.A)) if (!this._isInsideQuery && typeof(IQueryable).GetTypeInfo().IsAssignableFrom(linq.Type.GetTypeInfo())) { this._rootQuery = (IQueryable)value; return(ODataExpression.Query()); } return(ODataExpression.Constant(value, linq.Type)); } switch (linq.NodeType) { case ExpressionType.OrElse: return(this.TranslateBinary(linq, ODataBinaryOp.Or)); case ExpressionType.AndAlso: return(this.TranslateBinary(linq, ODataBinaryOp.And)); case ExpressionType.Add: if (linq.Type == typeof(string)) { // special case adding strings, since that's the same as Concat var binary = (BinaryExpression)linq; return(this.TranslateInternal(Expression.Call(Helpers.GetMethod(() => string.Concat(default(string), default(string))), binary.Left, binary.Right))); } return(this.TranslateBinary(linq, ODataBinaryOp.Add)); case ExpressionType.Subtract: return(this.TranslateBinary(linq, ODataBinaryOp.Subtract)); case ExpressionType.Multiply: return(this.TranslateBinary(linq, ODataBinaryOp.Multiply)); case ExpressionType.Divide: return(this.TranslateBinary(linq, ODataBinaryOp.Divide)); case ExpressionType.Modulo: return(this.TranslateBinary(linq, ODataBinaryOp.Modulo)); case ExpressionType.Equal: return(this.TranslateBinary(linq, ODataBinaryOp.Equal)); case ExpressionType.NotEqual: return(this.TranslateBinary(linq, ODataBinaryOp.NotEqual)); case ExpressionType.LessThan: return(this.TranslateBinary(linq, ODataBinaryOp.LessThan)); case ExpressionType.LessThanOrEqual: return(this.TranslateBinary(linq, ODataBinaryOp.LessThanOrEqual)); case ExpressionType.GreaterThan: return(this.TranslateBinary(linq, ODataBinaryOp.GreaterThan)); case ExpressionType.GreaterThanOrEqual: return(this.TranslateBinary(linq, ODataBinaryOp.GreaterThanOrEqual)); case ExpressionType.Not: return(ODataExpression.UnaryOp(this.TranslateInternal(((UnaryExpression)linq).Operand), ODataUnaryOp.Not)); case ExpressionType.Negate: // we translate -a.B as (-1 * a.B) for numeric types var negated = ((UnaryExpression)linq).Operand; var underlyingNegatedType = Nullable.GetUnderlyingType(negated.Type) ?? negated.Type; if (!underlyingNegatedType.IsNumeric()) { throw new ODataCompileException("Expression '" + linq + "' could not be translated to OData: only negation of numeric types is supported"); } var multiplyNegate = Expression.Multiply( Expression.Constant(Convert.ChangeType(-1, underlyingNegatedType), negated.Type), negated ); return(this.TranslateInternal(multiplyNegate)); case ExpressionType.MemberAccess: return(this._memberAndParameterTranslator.TranslateMemberAccess((MemberExpression)linq)); case ExpressionType.Convert: case ExpressionType.ConvertChecked: case ExpressionType.TypeAs: return(ODataExpression.Convert(this.TranslateInternal(((UnaryExpression)linq).Operand), linq.Type)); case ExpressionType.Parameter: return(this._memberAndParameterTranslator.TranslateParameter((ParameterExpression)linq)); case ExpressionType.TypeIs: var typeBinary = (TypeBinaryExpression)linq; var isArg = this.TranslateInternal(typeBinary.Expression); var isTypeConstant = ODataExpression.Constant(typeBinary.TypeOperand); return(isArg != null ? ODataExpression.Call(ODataFunction.IsOf, new[] { isArg, isTypeConstant }) : ODataExpression.Call(ODataFunction.IsOf, new[] { isTypeConstant })); case ExpressionType.Call: return(this.TranslateCall((MethodCallExpression)linq)); case ExpressionType.Quote: var quoted = (LambdaExpression)((UnaryExpression)linq).Operand; if (!this._isInsideQuery) { throw new ODataCompileException("Unexpected placement for lambda expression " + linq); } return(this.TranslateInternal(quoted.Body)); default: throw new ODataCompileException("Expression '" + linq + "' of type " + linq.NodeType + " could not be translated to OData"); } }