今天在百度知道中看到一個問題,研究了一會便回答了:
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)就可以了。
性能方面沒有測試,應該是可以使用緩存的。有興趣的朋友可以改一下。