你的位置:首页 > ASP.net教程

[ASP.net教程]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)就可以了。

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