bool CanBeCompiled(Expression expr) { return null == expr.Find(ex => { if (IsServerSideOnly(ex)) return true; switch (ex.NodeType) { case ExpressionType.Parameter : return ex != ParametersParam; case ExpressionType.MemberAccess : { var attr = GetFunctionAttribute(((MemberExpression)ex).Member); return attr != null && attr.ServerSideOnly; } case ExpressionType.Call : { var attr = GetFunctionAttribute(((MethodCallExpression)ex).Method); return attr != null && attr.ServerSideOnly; } } return false; }); }
bool CanBeConstant(Expression expr) { return null == expr.Find(ex => { if (ex is BinaryExpression || ex is UnaryExpression || ex.NodeType == ExpressionType.Convert) return false; switch (ex.NodeType) { case ExpressionType.Constant: { var c = (ConstantExpression)ex; if (c.Value == null || ExpressionHelper.IsConstant(ex.Type)) return false; break; } case ExpressionType.MemberAccess: { var ma = (MemberExpression)ex; if (ExpressionHelper.IsConstant(ma.Member.DeclaringType) || TypeHelper.IsNullableValueMember(ma.Member)) return false; break; } case ExpressionType.Call: { var mc = (MethodCallExpression)ex; if (ExpressionHelper.IsConstant(mc.Method.DeclaringType) || mc.Method.DeclaringType == typeof(object)) return false; var attr = GetFunctionAttribute(mc.Method); if (attr != null && !attr.ServerSideOnly) return false; break; } } return true; }); }
bool CanBeTranslatedToSql(IParseContext context, Expression expr, bool canBeCompiled) { return null == expr.Find(pi => { switch (pi.NodeType) { case ExpressionType.MemberAccess: { var ma = (MemberExpression)pi; var l = ConvertMember(ma.Member); if (l != null) return !CanBeTranslatedToSql(context, l.Body.Unwrap(), canBeCompiled); var attr = GetFunctionAttribute(ma.Member); if (attr == null && !TypeHelper.IsNullableValueMember(ma.Member)) goto case ExpressionType.Parameter; break; } case ExpressionType.Parameter: { if (canBeCompiled && GetContext(context, pi) == null) return !CanBeCompiled(pi); break; } case ExpressionType.Call: { var e = pi as MethodCallExpression; if (e.Method.DeclaringType != typeof(Enumerable)) { var cm = ConvertMethod(e); if (cm != null) return !CanBeTranslatedToSql(context, cm, canBeCompiled); var attr = GetFunctionAttribute(e.Method); if (attr == null && canBeCompiled) return !CanBeCompiled(pi); } break; } case ExpressionType.New: return true; } return false; }); }
bool CheckSubQueryForWhere(IParseContext context, Expression expression, out bool makeHaving) { //var checkParameter = true; //context.IsExpression(expression, 0, RequestFor.ScalarExpression); var makeSubQuery = false; var isHaving = false; var isWhere = false; expression.Find(expr => { if (IsSubQuery(context, expr)) return isWhere = true; var stopWalking = false; switch (expr.NodeType) { case ExpressionType.MemberAccess: { var ma = (MemberExpression)expr; if (TypeHelper.IsNullableValueMember(ma.Member)) break; if (ConvertMember(ma.Member) == null) { var ctx = GetContext(context, expr); if (ctx != null) { if (ctx.IsExpression(expr, 0, RequestFor.Expression)) makeSubQuery = true; stopWalking = true; } } isWhere = true; break; } case ExpressionType.Call: { var e = (MethodCallExpression)expr; if (e.Method.DeclaringType == typeof(Enumerable) && e.Method.Name != "Contains") return isHaving = true; isWhere = true; break; } case ExpressionType.Parameter: { var ctx = GetContext(context, expr); if (ctx != null) { if (ctx.IsExpression(expr, 0, RequestFor.Expression)) makeSubQuery = true; stopWalking = true; } isWhere = true; break; } } return stopWalking; }); makeHaving = isHaving && !isWhere; return makeSubQuery || isHaving && isWhere; }
static Expression FindExpression(Expression expr) { var ret = expr.Find(pi => { switch (pi.NodeType) { case ExpressionType.Convert : { var e = (UnaryExpression)expr; return e.Operand.NodeType == ExpressionType.ArrayIndex && ((BinaryExpression)e.Operand).Left == ParametersParam; } case ExpressionType.MemberAccess : case ExpressionType.New : return true; } return false; }); if (ret == null) throw new NotImplementedException(); return ret; }