• C# ORM中Dto Linq Expression 和 数据库Model Linq Expression之间的转换


    今天在百度知道中看到一个问题,研究了一会便回答了:

    http://zhidao.baidu.com/question/920461189016484459.html

    如何使dto linq 表达式转换到数据库实体对象linq表达式。自己搜集了一些资料然后实战了一下,还是可行。

    自己扩展的一个方法 Cast<TInput, TToProperty>(this Expression<Func<TInput, bool>> expression),代码如下:

    namespace System
    {
        public static class LambdaExpressionExtensions
        {
            private static Expression Parser(ParameterExpression parameter, Expression expression)
            {
                if (expression == null) return null;
                switch (expression.NodeType)
                {
                    //一元运算符
                    case ExpressionType.Negate:
                    case ExpressionType.NegateChecked:
                    case ExpressionType.Not:
                    case ExpressionType.Convert:
                    case ExpressionType.ConvertChecked:
                    case ExpressionType.ArrayLength:
                    case ExpressionType.Quote:
                    case ExpressionType.TypeAs:
                        {
                            var unary = expression as UnaryExpression;
                            var exp = Parser(parameter, unary.Operand);
                            return Expression.MakeUnary(expression.NodeType, exp, unary.Type, unary.Method);
                        }
                    //二元运算符
                    case ExpressionType.Add:
                    case ExpressionType.AddChecked:
                    case ExpressionType.Subtract:
                    case ExpressionType.SubtractChecked:
                    case ExpressionType.Multiply:
                    case ExpressionType.MultiplyChecked:
                    case ExpressionType.Divide:
                    case ExpressionType.Modulo:
                    case ExpressionType.And:
                    case ExpressionType.AndAlso:
                    case ExpressionType.Or:
                    case ExpressionType.OrElse:
                    case ExpressionType.LessThan:
                    case ExpressionType.LessThanOrEqual:
                    case ExpressionType.GreaterThan:
                    case ExpressionType.GreaterThanOrEqual:
                    case ExpressionType.Equal:
                    case ExpressionType.NotEqual:
                    case ExpressionType.Coalesce:
                    case ExpressionType.ArrayIndex:
                    case ExpressionType.RightShift:
                    case ExpressionType.LeftShift:
                    case ExpressionType.ExclusiveOr:
                        {
                            var binary = expression as BinaryExpression;
                            var left = Parser(parameter, binary.Left);
                            var right = Parser(parameter, binary.Right);
                            var conversion = Parser(parameter, binary.Conversion);
                            if (binary.NodeType == ExpressionType.Coalesce && binary.Conversion != null)
                            {
                                return Expression.Coalesce(left, right, conversion as LambdaExpression);
                            }
                            else
                            {
                                return Expression.MakeBinary(expression.NodeType, left, right, binary.IsLiftedToNull, binary.Method);
                            }
                        }
                    //其他
                    case ExpressionType.Call:
                        {
                            var call = expression as MethodCallExpression;
                            List<Expression> arguments = new List<Expression>();
                            foreach (var argument in call.Arguments)
                            {
                                arguments.Add(Parser(parameter, argument));
                            }
                            var instance = Parser(parameter, call.Object);
                            call = Expression.Call(instance, call.Method, arguments);
                            return call;
                        }
                    case ExpressionType.Lambda:
                        {
                            var Lambda = expression as LambdaExpression;
                            return Parser(parameter, Lambda.Body);
                        }
                    case ExpressionType.MemberAccess:
                        {
                            var memberAccess = expression as MemberExpression;
                            if (memberAccess.Expression == null)
                            {
                                memberAccess = Expression.MakeMemberAccess(null, memberAccess.Member);
                            }
                            else
                            {
                                var exp = Parser(parameter, memberAccess.Expression);
                                var member = exp.Type.GetMember(memberAccess.Member.Name).FirstOrDefault();
                                memberAccess = Expression.MakeMemberAccess(exp, member);
                            }
                            return memberAccess;
                        }
                    case ExpressionType.Parameter:
                        return parameter;
                    case ExpressionType.Constant:
                        return expression;
                    case ExpressionType.TypeIs:
                        {
                            var typeis = expression as TypeBinaryExpression;
                            var exp = Parser(parameter, typeis.Expression);
                            return Expression.TypeIs(exp, typeis.TypeOperand);
                        }
                    default:
                        throw new Exception(string.Format("Unhandled expression type: '{0}'", expression.NodeType));
                }
            }
            public static Expression<Func<TToProperty, bool>> Cast<TInput, TToProperty>(this Expression<Func<TInput, bool>> expression)
            {
                var p = Expression.Parameter(typeof(TToProperty), "p");
                var x = Parser(p, expression);
                return Expression.Lambda<Func<TToProperty, bool>>(x, p);
            }
        }
    }

    比如有如下的 实体类对象:

        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
        public class UserDto
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }

    简单的测试代码:

        class Program
        {
            static int[] array0 = new[] { 0, 1 };
            static void Main1(string[] args)
            {
                var array1 = new[] { 0, 1 };
                Expression<Func<UserDto, bool>> exp = null;
                Expression<Func<User, bool>> exp2 = null;
    
                //====exp====
                //exp = u => u.Name == "张三";
                //exp = u => u.Id.Equals(1);
                //exp = u => u.Id.Equals(1) && u.Name == "张三";
                //exp = u => u.Id.Equals(1) && u.Name == "张三" || u.Name == "张三";
                //exp = u => Filter(u.Name);
                //exp = u => !Filter(u.Name);
                //exp = u => u.Id.Equals(1) && u.Name == "张三" && Filter(u.Name);
                //exp = u => array1.Contains(u.Id);
                //exp = u => array1.Contains(u.Id) || u.Name == "张三";
                //exp = u => array0.Contains(u.Id);
                //exp = u => u.Id > 0;
                //exp = u => u.Id < 10;
                //exp = u => u.Id * 2 < 10;
                //exp = u => u.Id - 2 < 10;
                //exp = u => u.Id + 2 < 10;
                //exp = u => u.Id / 2 < 10;
                //exp = u => (int)(u.Id / 2) < 10;
                //exp = u => u.Name is string;
                //exp = u => ((object)u.Id).ToString() == "1";
                //exp = u => u.Id == default(int);
                //exp = u => true;
                //exp = u => Math.Abs(u.Id)==1;
                exp = u =>
                            u.Id.Equals(1)
                            && u.Name == "张三"
                            && u.Id < 10
                            && array1.Contains(u.Id)
                            && u.Id + 2 < 10
                            && (((object)u.Id).ToString() == "1" || u.Name.Contains(""))
                            && Math.Abs(u.Id) == 1
                            && Filter(u.Name)
                            && true
                            ;
                //=====exp2=====
                exp2 = exp.Cast<UserDto, User>();
                Console.WriteLine(exp.ToString());
                Console.WriteLine(exp.ToString());
    
    
    
                //测试数据
                List<User> list = new List<User>() { 
                    new User{ Id=0,Name="AAA"},
                    new User{ Id=1,Name="张三"},
                    new User{ Id=2,Name="李四"}
                };
                var item = list.Where(exp2.Compile()).FirstOrDefault();
                Console.WriteLine(item.Name);
                Console.ReadKey();
            }
    
            public static bool Filter(string name)
            {
                return name.Contains("");
            }
        }

    应该说常用的筛选条件都是支持的。这里的list由于没有数据库环境就用List<User>模拟的,真实ORM环境换成list.Where(exp2)就可以了。

    性能方面没有测试,应该是可以使用缓存的。有兴趣的朋友可以改一下。

    作者:SplendidDream
    出处:http://www.cnblogs.com/SplendidDream/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    以下哪个Hibernate主键生成策略是实现主键按数值顺序递增的?
    编写一个Filter,除继承HttpServlet类外还需要( )。
    有关JSP隐式对象,以下( )描述正确。
    JAVA通信系列三:Netty入门总结
    JAVA通信系列二:mina入门总结
    JAVA通信系列一:Java Socket技术总结
    大型网站架构系列:缓存在分布式系统中的应用(三)
    大型网站架构系列:缓存在分布式系统中的应用(二)
    大型网站架构系列:缓存在分布式系统中的应用(一)
    大型网站架构系列:负载均衡详解(4)
  • 原文地址:https://www.cnblogs.com/SplendidDream/p/ORM-Dto-Linq-Expression-to-Entity-Linq-Expression.html
Copyright © 2020-2023  润新知