Проблема синтаксического анализа дерева выражений LINQ - PullRequest
0 голосов
/ 25 января 2012

Я разрабатываю простой класс, который отображает любые кортежи из базы данных, по соглашению, в объекты CLR.

Здесь, в моей работе, я не могу использовать EntityFramework, потому что база данных гигантская, и мы разделили модели иневозможно пересечь разные контексты.

Так что я начал разрабатывать свой собственный ORM mapper, который генерирует команды вставки, обновления и удаления.я пытаюсь разработать метод выбора, который генерирует выбор CMD.

Этот метод получает фильтр Expression<T, bool> по параметру, который я хочу фильтровать данные.

Одна вещь, которую я действительно хочуиспользовать что-то вроде:

int value = 1;
int valu2 = 40;

mapper.Select<MyEntity>(m => m.id> value && m.id<= value2);

Большая проблема в том, что filter.body.toString() генерирует строку как есть, и что я действительно хочу сделать, это заменить значения «value» и «value2»по их значениям, объявленным по их переменным ...

Кто-то может подсказать мне?

Действительно, спасибо всем!

Ответы [ 2 ]

1 голос
/ 25 января 2012

Нет простого способа достичь этого.Вам придется рекурсивно проанализировать все синтаксическое дерево и преобразовать его в предложение where, которое выглядит следующим образом:

WHERE id > 1 AND id < 40

Смотрите блог на Дерево выраженийОсновы .Это не полный ответ на ваш вопрос;однако, это может дать вам отправную точку.

0 голосов
/ 27 января 2012

Я проанализировал дерево expr простым способом, просто чтобы построить фильтр.

Вот как я это сделал.

private static String ParseFilter(Expression expr)
    {
        return ParseFilter(expr, new ExpressionUtilFilterClass()).data.ToString();
    }

    // Recursive algorithm
    private
    static
    ExpressionUtilFilterClass                            // Return type
    ParseFilter(
        Expression expr,
        ExpressionUtilFilterClass info          // Used to pass information in recursive manner
    )
    {

        Type exprType = expr.GetType();

        if ( exprType != typeof(BinaryExpression) && exprType != typeof(MemberExpression) && exprType != typeof(ConstantExpression) )
            throw new InvalidOperationException("unsupported filter");


        if ( exprType == typeof(BinaryExpression) )
        {
            //
            // We have 2 expressions (left and right)
            // 

            BinaryExpression bExpr = (BinaryExpression)expr;
            ExpressionUtilFilterClass recursion;

            StringBuilder subOperation = new StringBuilder();
            recursion = ParseFilter(bExpr.Left, info);              // Go left in depth - we don't know the type yet

            subOperation.Append("( ");
            subOperation.Append(recursion.data);
            subOperation.Append(" ");

            subOperation.Append(_expressionOperator[bExpr.NodeType]);
            subOperation.Append(" ");

            recursion = ParseFilter(bExpr.Right, recursion);               // Pass reference that contains type information!

            subOperation.Append(recursion.data);
            subOperation.Append(" )");

            // Affect data subpart and pass to upper caller
            recursion.data = subOperation.ToString();

            return recursion;
        }

        else
        {
            MemberExpression mExpr;
            ParameterExpression pExpr;
            ConstantExpression cExpr;

            //
            // We need distinct if we are accessing to capturated variables (need map to sql) or constant variables
            //

            if ( ( mExpr = expr as MemberExpression ) != null )
            {
                if ( ( pExpr = ( mExpr.Expression as ParameterExpression ) ) != null )
                {
                    info.parameterType = mExpr.Expression.Type;        // Type of parameter (must be untouched)
                    info.data = GetMappingForProperty(info.parameterType, mExpr.Member.Name);                     // Must have a map to SQL (criar metodo que faz mapeamento)!!!!!!!!!!!!!!!!!

                    return info;
                }
                else
                {
                    cExpr = (ConstantExpression)mExpr.Expression;

                    object obj = cExpr.Value;               // Get anonymous object
                    string objField = mExpr.Member.Name;

                    FieldInfo value = obj.GetType().GetField(objField);  // Read native value
                    string nativeData = value.GetValue(obj).ToString();

                    info.data = nativeData;
                    return info;
                }
            }
            else
            {
                cExpr = (ConstantExpression)expr;
                string nativeData = cExpr.Value.ToString();

                info.data = nativeData;
                return info;
            }
        }
    }
...