bool PreferServerSide(Expression expr)
        {
            switch (expr.NodeType)
            {
            case ExpressionType.MemberAccess:
            {
                var pi = (MemberExpression)expr;
                var l  = SqlProvider.ConvertMember(pi.Member);

                if (l != null)
                {
                    var info = l.Body.Unwrap();

                    if (l.Parameters.Count == 1 && pi.Expression != null)
                    {
                        info = info.Convert(wpi => wpi == l.Parameters[0] ? pi.Expression : wpi);
                    }

                    return(info.Find(PreferServerSide) != null);
                }

                var attr = GetFunctionAttribute(pi.Member);
                return(attr != null && attr.PreferServerSide && !CanBeCompiled(expr));
            }

            case ExpressionType.Call:
            {
                var pi = (MethodCallExpression)expr;
                var e  = pi;
                var l  = SqlProvider.ConvertMember(e.Method);

                if (l != null)
                {
                    return(l.Body.Unwrap().Find(PreferServerSide) != null);
                }

                var attr = GetFunctionAttribute(e.Method);
                return(attr != null && attr.PreferServerSide && !CanBeCompiled(expr));
            }
            }

            return(false);
        }
        public Expression BuildExpression(IBuildContext context, Expression expression)
        {
            var newExpr = expression.Convert2(pi =>
            {
                if (_skippedExpressions.Contains(pi))
                {
                    return(new ExpressionHelper.ConvertInfo(pi, true));
                }

                switch (pi.NodeType)
                {
                case ExpressionType.MemberAccess:
                    {
                        if (IsServerSideOnly(pi) || PreferServerSide(pi))
                        {
                            return(new ExpressionHelper.ConvertInfo(BuildSql(context, pi)));
                        }

                        var ma = (MemberExpression)pi;

                        if (SqlProvider.ConvertMember(ma.Member) != null)
                        {
                            break;
                        }

                        /*
                         * var res = context.IsExpression(pi, 0, RequestFor.Association);
                         *
                         * if (res.Result)
                         * {
                         *      var table = (TableBuilder.AssociatedTableContext)res.Context;
                         *
                         *      if (table.IsList)
                         *              return new ExpressionHelper.ConvertInfo(BuildMultipleQuery(context, pi));
                         * }
                         */

                        var ctx = GetContext(context, pi);

                        if (ctx != null)
                        {
                            return(new ExpressionHelper.ConvertInfo(ctx.BuildExpression(pi, 0)));
                        }

                        var ex = ma.Expression;

                        if (ex != null && ex.NodeType == ExpressionType.Constant)
                        {
                            // field = localVariable
                            //
                            var c = _expressionAccessors[ex];
                            return(new ExpressionHelper.ConvertInfo(
                                       Expression.MakeMemberAccess(Expression.Convert(c, ex.Type), ma.Member)));
                        }

                        break;
                    }

                case ExpressionType.Parameter:
                    {
                        if (pi == ParametersParam)
                        {
                            break;
                        }

                        var ctx = GetContext(context, pi);

                        if (ctx != null)
                        {
                            return(new ExpressionHelper.ConvertInfo(ctx.BuildExpression(pi, 0)));
                        }

                        break;
                    }

                case ExpressionType.Constant:
                    {
                        if (ExpressionHelper.IsConstant(pi.Type))
                        {
                            break;
                        }

                        if (_expressionAccessors.ContainsKey(pi))
                        {
                            return(new ExpressionHelper.ConvertInfo(Expression.Convert(_expressionAccessors[pi], pi.Type)));
                        }

                        break;
                    }

                case ExpressionType.Coalesce:

                    if (pi.Type == typeof(string) && MappingSchema.GetDefaultNullValue <string>() != null)
                    {
                        return(new ExpressionHelper.ConvertInfo(BuildSql(context, pi)));
                    }

                    if (CanBeTranslatedToSql(context, ConvertExpression(pi), true))
                    {
                        return(new ExpressionHelper.ConvertInfo(BuildSql(context, pi)));
                    }

                    break;

                case ExpressionType.Conditional:

                    if (CanBeTranslatedToSql(context, ConvertExpression(pi), true))
                    {
                        return(new ExpressionHelper.ConvertInfo(BuildSql(context, pi)));
                    }
                    break;

                case ExpressionType.Call:
                    {
                        var ce = (MethodCallExpression)pi;

                        if (IsGroupJoinSource(context, ce))
                        {
                            foreach (var arg in ce.Arguments.Skip(1))
                            {
                                if (!_skippedExpressions.Contains(arg))
                                {
                                    _skippedExpressions.Add(arg);
                                }
                            }

                            break;
                        }

                        if (IsSubQuery(context, ce))
                        {
                            if (TypeHelper.IsSameOrParent(typeof(IEnumerable), pi.Type))
                            {
                                return(new ExpressionHelper.ConvertInfo(BuildMultipleQuery(context, pi)));
                            }

                            return(new ExpressionHelper.ConvertInfo(GetSubQuery(context, ce).BuildExpression(null, 0)));
                        }

                        if (IsServerSideOnly(pi) || PreferServerSide(pi))
                        {
                            return(new ExpressionHelper.ConvertInfo(BuildSql(context, pi)));
                        }
                    }

                    break;
                }

                if (EnforceServerSide(context))
                {
                    switch (pi.NodeType)
                    {
                    case ExpressionType.MemberInit:
                    case ExpressionType.New:
                    case ExpressionType.Convert:
                        break;

                    default:
                        if (CanBeCompiled(pi))
                        {
                            break;
                        }
                        return(new ExpressionHelper.ConvertInfo(BuildSql(context, pi)));
                    }
                }

                return(new ExpressionHelper.ConvertInfo(pi));
            });

            return(newExpr);
        }
        public Expression BuildExpression(IBuildContext context, Expression expression)
        {
            var newExpr = expression.Convert2(expr =>
            {
                if (_skippedExpressions.Contains(expr))
                {
                    return(new ExpressionHelper.ConvertInfo(expr, true));
                }

                if (expr.Find(IsNoneSqlMember) != null)
                {
                    return(new ExpressionHelper.ConvertInfo(expr));
                }

                switch (expr.NodeType)
                {
                case ExpressionType.MemberAccess:
                    {
                        if (IsServerSideOnly(expr) || PreferServerSide(expr))
                        {
                            return(new ExpressionHelper.ConvertInfo(BuildSql(context, expr)));
                        }

                        var ma = (MemberExpression)expr;

                        if (SqlProvider.ConvertMember(ma.Member) != null)
                        {
                            break;
                        }

                        var ctx = GetContext(context, expr);

                        if (ctx != null)
                        {
                            return(new ExpressionHelper.ConvertInfo(ctx.BuildExpression(expr, 0)));
                        }

                        var ex = ma.Expression;

                        if (ex != null && ex.NodeType == ExpressionType.Constant)
                        {
                            // field = localVariable
                            //
                            var c = _expressionAccessors[ex];
                            return(new ExpressionHelper.ConvertInfo(
                                       Expression.MakeMemberAccess(Expression.Convert(c, ex.Type), ma.Member)));
                        }

                        break;
                    }

                case ExpressionType.Parameter:
                    {
                        if (expr == ParametersParam)
                        {
                            break;
                        }

                        var ctx = GetContext(context, expr);

                        if (ctx != null)
                        {
                            return(new ExpressionHelper.ConvertInfo(ctx.BuildExpression(expr, 0)));
                        }

                        break;
                    }

                case ExpressionType.Constant:
                    {
                        if (ExpressionHelper.IsConstant(expr.Type))
                        {
                            break;
                        }

                        if (_expressionAccessors.ContainsKey(expr))
                        {
                            return(new ExpressionHelper.ConvertInfo(Expression.Convert(_expressionAccessors[expr], expr.Type)));
                        }

                        break;
                    }

                case ExpressionType.Coalesce:

                    if (expr.Type == typeof(string) && MappingSchema.GetDefaultNullValue <string>() != null)
                    {
                        return(new ExpressionHelper.ConvertInfo(BuildSql(context, expr)));
                    }

                    if (CanBeTranslatedToSql(context, ConvertExpression(expr), true))
                    {
                        return(new ExpressionHelper.ConvertInfo(BuildSql(context, expr)));
                    }

                    break;

                case ExpressionType.Conditional:

                    if (CanBeTranslatedToSql(context, ConvertExpression(expr), true))
                    {
                        return(new ExpressionHelper.ConvertInfo(BuildSql(context, expr)));
                    }
                    break;

                case ExpressionType.Call:
                    {
                        var ce = (MethodCallExpression)expr;

                        if (IsGroupJoinSource(context, ce))
                        {
                            foreach (var arg in ce.Arguments.Skip(1))
                            {
                                if (!_skippedExpressions.Contains(arg))
                                {
                                    _skippedExpressions.Add(arg);
                                }
                            }

                            break;
                        }

                        if (IsSubQuery(context, ce))
                        {
                            if (TypeHelper.IsSameOrParent(typeof(IEnumerable), expr.Type) && expr.Type != typeof(string) && !expr.Type.IsArray)
                            {
                                return(new ExpressionHelper.ConvertInfo(BuildMultipleQuery(context, expr)));
                            }

                            return(new ExpressionHelper.ConvertInfo(GetSubQuery(context, ce).BuildExpression(null, 0)));
                        }

                        if (IsServerSideOnly(expr) || PreferServerSide(expr))
                        {
                            return(new ExpressionHelper.ConvertInfo(BuildSql(context, expr)));
                        }
                    }

                    break;
                }

                if (EnforceServerSide(context))
                {
                    switch (expr.NodeType)
                    {
                    case ExpressionType.MemberInit:
                    case ExpressionType.New:
                    case ExpressionType.Convert:
                        break;

                    default:
                        if (CanBeCompiled(expr))
                        {
                            break;
                        }
                        return(new ExpressionHelper.ConvertInfo(BuildSql(context, expr)));
                    }
                }

                return(new ExpressionHelper.ConvertInfo(expr));
            });

            return(newExpr);
        }