来源:Poiuyt_cyc
链接:http://www.cnblogs.com/irenebbkiss/p/4157364.html
/// /// 根据条件生成对应的sql查询操作符 /// /// /// private string GetOperator(ExpressionType expressiontype) { switch (expressiontype) { case ExpressionType.And: return 'and'; case ExpressionType.AndAlso: return 'and'; case ExpressionType.Or: return 'or'; case ExpressionType.OrElse: return 'or'; case ExpressionType.Equal: return '='; case ExpressionType.NotEqual: return ''; case ExpressionType.LessThan: return ''; case ExpressionType.LessThanOrEqual: return ''; case ExpressionType.GreaterThan: return '>'; case ExpressionType.GreaterThanOrEqual: return '>='; default: throw new Exception(string.Format('不支持{0}此种运算符查找!' + expressiontype)); } }
private string ResolveFunc(Expression left, Expression right, ExpressionType expressiontype) { var Name = (left as MemberExpression).Member.Name; var Value = (right as ConstantExpression).Value; var Operator = GetOperator(expressiontype); string CompName = SetArgument(Name, Value.ToString()); string Result = string.Format('({0} {1} {2})', Name, Operator, CompName); return Result; } private string ResolveLinqToObject(Expression expression, object value, ExpressionType? expressiontype = null) { var MethodCall = expression as MethodCallExpression; var MethodName = MethodCall.Method.Name; switch (MethodName)//这里其实还可以改成反射调用,不用写switch { case 'Contains': if (MethodCall.Object != null) return Like(MethodCall); return In(MethodCall, value); case 'Count': return Len(MethodCall, value, expressiontype.Value); case 'LongCount': return Len(MethodCall, value, expressiontype.Value); default: throw new Exception(string.Format('不支持{0}方法的查找!', MethodName)); } } private string SetArgument(string name, string value) { name = '@' + name; string temp = name; while (Argument.ContainsKey(temp)) { int code = Guid.NewGuid().GetHashCode(); if (code 0) code *= -1; temp = name + code; } Argument[temp] = value; return temp; } private string In(MethodCallExpression expression, object isTrue) { var Argument1 = (expression.Arguments[0] as MemberExpression).Expression as ConstantExpression; var Argument2 = expression.Arguments[1] as MemberExpression; var Field_Array = Argument1.Value.GetType().GetFields().First(); object[] Array = Field_Array.GetValue(Argument1.Value) as object[]; Liststring> SetInPara = new Liststring>(); for (int i = 0; i ) { string Name_para = 'InParameter' + i; string Value = Array[i].ToString(); string Key = SetArgument(Name_para, Value); SetInPara.Add(Key); } string Name = Argument2.Member.Name; string Operator = Convert.ToBoolean(isTrue) ? 'in' : ' not in'; string CompName = string.Join(',', SetInPara); string Result = string.Format('{0} {1} ({2})', Name, Operator, CompName); return Result; } private string Like(MethodCallExpression expression) { object Temp_Vale = (expression.Arguments[0] as ConstantExpression).Value; string Value = string.Format('%{0}%', Temp_Vale); string Name = (expression.Object as MemberExpression).Member.Name; string CompName = SetArgument(Name, Value); string Result = string.Format('{0} like {1}', Name, CompName); return Result; } private string Len(MethodCallExpression expression, object value, ExpressionType expressiontype) { object Name = (expression.Arguments[0] as MemberExpression).Member.Name; string Operator = GetOperator(expressiontype); string CompName = SetArgument(Name.ToString(), value.ToString()); string Result = string.Format('len({0}){1}{2}', Name, Operator, CompName); return Result; } }
static void Main(string[] args) { string[] Names = { 'Andy', 'Amy', 'Mike' }; Expressionbool>> func = x => (!Names.Contains(x.Name) & (x.Name == 'A' || x.Name.Count() > 5)); ResolveExpress resolve = new ResolveExpress(); resolve.ResolveExpression(func); Console.WriteLine(resolve.SqlWhere); foreach (var item in resolve.Paras) { Console.WriteLine(item.ParameterName + ':' + item.Value); } Console.ReadKey(); }
结果:
这里有几个重要的东西要给大家讲下
string[] Names={“Andy”,”Amy”,”Mike”};
1.)x => Names.Contains(x.Name);
2.)x => Names.Contains(x.Name)==false;
3.)x => !Names.Contains(x.Name);
这3种在Expression中的表现都不一样
1的话会看成是一个静态方法(MethodCallExpression)
2的话会看成是一个2元运算(BinaryExpression)
3的话会看成是一个1元运算(UnaryExpression)
所以我们都要支持,处理都有所不同。
还有
x=>x.Birthday
string name=”123″;
x=>x.Name==name;
和
x=>x.Name==”123″
的处理也不一样。大家可以在例子中细细的看看。
这样的构造使得我们切换数据库变得非常简单。因为我们程序中的查询都是基于lambda。换了数据库只要添加一个对应的lamdba转数据库查询条件的实现就可以了。写得够多了。至于数据层怎么封装,到了这一步它已经变得没什么难度了。希望大家能从文章中有所启发和帮助
下篇文章将结合解析Expression和IQueryable来实现延迟加载
补充点东西
IEnumerable和IQueryable有什么不同?
为什么EF查询后返回的是IQueryable而不是IEnumerable。我们对着IQueryableF12去看看。
啥都没,就继承了几个接口。鼠标移到IQueryable上。F12
IQueryable中有3个属性。
Type是类型。
Expresstion是表达式。
那IQueryProvider是什么?
再看看IQueryProvider接口的定义。
CreateQuery是创建查询条件
Execute是执行查询(通常在GetEnumerator()中调用)
当我们IQueryable.Where(x=>x.xxx==”123″)时。其实Where方法内部应该是调用了IQueryable接口中的IQueryProvider属性的CreateQuery(Expresstion expresstion)方法,然后将方法的返回值又返回出来。
而参数(Expresstion )呢?则是IQueryable.Where(x=>x.xxx==”123″)2部分的Expresstion相并。所以IQueryable只是创建条件。所以51楼的朋友说得非常对。
那什么时候执行呢?因为我们的IQueryable继承了IEnumabler,所以我们必须实现GetEnumerator()。我们ToList或foreach时,其实就会调用GetEnumerator()。这时我们就调用Execute进行解析Expresstion,从而得到我们想要的结果。
总结就是IQueryable只是创建条件,当我们调用a.Where(x=>xxx)时,其实是将a与后面的条件相并,生成一个新的IQueryable。当我们foreach时就会调用GetEnumerator()。这时我们一般会调用IQueryProvider里的Execute去解析Expresstion并查询出我们想要的结果
我也知道这篇文章介绍的和我们所说的“ORM”相差很远,但是所谓的ORM最复杂的莫非查询部分了,而依照我这思路走下去,我觉得是可以自己完成一个的。
|