LINQ 表达式树解析问题

发布于 2024-12-28 23:15:12 字数 555 浏览 0 评论 0原文

我正在开发一个简单的类,按照约定将数据库中的任何元组映射到 CLR 对象。

在我的工作中,我不能使用 EntityFramework,因为数据库很大,而且我们有分割的模型,不可能跨越不同的上下文。

所以我开始开发自己的 ORM 映射器,它生成插入、更新和删除命令。 我正在尝试开发生成选择 CMD 的选择方法。

此方法通过我想要过滤数据的参数接收 Expression 过滤器。

我真正想要使用的一件事是:

int value = 1;
int valu2 = 40;

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

最大的问题是 filter.body.toString() 按原样生成一个字符串,并且我真正想做的是替换值“value”和“value2”的变量声明的值......

有人可以给我一盏灯吗?

真的非常感谢大家!

I am developing a simple class that maps any Tuples from database, by convention, to CLR objects.

Here in my work, i cannot use EntityFramework, because database is giant and we have splitted models and is impossible to cross different contexts.

So i started develop my own ORM mapper, that generate insert, update and delete commands.
i am trying to develop the select method, that generates select CMD.

This method receives a Expression<T, bool> filter by parameter that i want to filter the data.

One thing that i really want to use is something like:

int value = 1;
int valu2 = 40;

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

The big problem is that filter.body.toString() generates a string as is, and, what i really want to do is to replace the values of "value" and "value2" by their values declared on their variables...

Someone can give me a light?

Really Thanks to all!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧情别恋 2025-01-04 23:15:12

没有简单的方法可以实现这一目标。您必须以递归方式解析整个语法树并将其转换为 where 子句,如下所示:

WHERE id > 1 且 id < 40

请参阅 上的博客表达式树基础知识。这不是您问题的完整答案;但是,它可能会给您一个起点。

There is no simple way to achieve this. You will have to parse the entire syntax tree in a recursive manner and convert it to a where clause, which looks like this:

WHERE id > 1 AND id < 40

See a blog on Expression Tree Basics. It is not the full answer to your question; however, it may give you a starting point.

笑,眼淚并存 2025-01-04 23:15:12

我以简单的方式解析了 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;
            }
        }
    }

I parsed the expr tree in a simple manner, just to build the filter.

Here's how i did it.

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;
            }
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文