抛弃EF,20分构建一个属于自己的ORM框架 - Poiuyt_cyc - 博客园
Excerpt 相信EF大家都不陌生了,因为数据库表跟程序实体是一一对应的原因,我们能够通过lambda这种函数式的编程方式进行操作数据库,感觉非常清晰明了。与我们直接写SQL相比,lambda是强类型,拥有更好的扩展性,伸缩性,而且编程更加的方便,快捷。。下面我们就基于Expression和lambda来与大家构
相信EF大家都不陌生了,因为数据库表跟程序实体是一一对应的原因,我们能够通过lambda这种函数式的编程方式进行操作数据库,感觉非常清晰明了。与我们直接写SQL相比,lambda是强类型,拥有更好的扩展性,伸缩性,而且编程更加的方便,快捷。。下面我们就基于Expression和lambda来与大家构建一个属于自己的ORM框架。
思路的话很简单,就是将lambda转换成我们对应的数据库所需的查询条件,然后执行查询,再将结果以反射的方式封装成List返回出去。
Expression
大家使用EF的时候多多少少会留意到有Expression这个东西。特别是查询时会看到要你传入Expression<Func<T,bool>>这样类型的参数,它又和Func<T,bool>有什么比同呢?
Expression<Func<T,bool>>是表达式树,我们可以通过它来分析我们的委托中的函数。当调用Compile方法后就会变成委托,才能执行。
Func<T,bool>只是一个普通的委托。
例如我们现在有个实体类Staff
1 2 3 4 5 6 7 8 <span>public</span> <span>class</span><span> Staff { </span><span>public</span> <span>string</span> Name { <span>get</span>; <span>set</span><span>; } </span><span>public</span> <span>int</span> Age { <span>get</span>; <span>set</span><span>; } </span><span>public</span> <span>string</span> Code { <span>get</span>; <span>set</span><span>; } </span><span>public</span> DateTime? Birthday { <span>get</span>; <span>set</span><span>; } </span><span>public</span> <span>bool</span> Deletion { <span>get</span>; <span>set</span><span>; } }</span>
我们还有一个这样的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 <span>class</span><span> Program { </span><span>static</span> <span>void</span> Main(<span>string</span><span>[] args) { FindAs</span><Staff>(x => x.Code == <span>"</span><span>张三</span><span>"</span> && x.Name.Contains(<span>"</span><span>张</span><span>"</span><span>)); } </span><span>public</span> <span>static</span> List<T> FindAs<T>(Expression<Func<T, <span>bool</span>>><span> func) { </span><span>//</span><span>将func转换成对应数据库的查询条件,然后执行查询</span> <span>return</span> <span>null</span>;<span>//</span><span>将结果返回</span> <span> } }</span>
我们希望通过 FindAs(x => x.Age <50 && x.Name.Contains(“张”)); 就能查询出Staff表中Age<50并且Name包含有“张”字的人的信息。而生成的sql语句应该是select * from staff where Age<50 and Name like ‘%张%’。现在我们就来分析下这个func
从上面的图我们可以看到当前的Expression是一个lambda表达式,我们点开它的body看看。
我们可以看到body里分为左边和右边,还有NodeType。和我们的lambda对比下看看’x => x.Code ==”张三” && x.Name.Contains(“张”)’是不是找到点灵感了?我们再继续把左边和右边拆开看看。
可以看到我们需要的信息都有了,看来转换成SQL已经不是什么难事了,动手开搞了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 <span>class</span><span> Program { </span><span>static</span> <span>void</span> Main(<span>string</span><span>[] args) { FindAs</span><Staff>(x => x.Code == <span>"</span><span>张三</span><span>"</span> && x.Name.Contains(<span>"</span><span>张</span><span>"</span><span>)); FindAs</span><Staff>(x => x.Age <= <span>12</span> && x.Name.Contains(<span>"</span><span>张</span><span>"</span><span>)); Console.ReadKey(); } </span><span>public</span> <span>static</span> List<T> FindAs<T>(Expression<Func<T, <span>bool</span>>><span> func) { BinaryExpression Binary </span>= func.Body <span>as</span><span> BinaryExpression; </span><span>string</span> left =<span> ResovleFunc(Binary.Left); </span><span>string</span> right =<span> ResovleLinqToObject(Binary.Right); </span><span>string</span> oper =<span> GetOperator(Binary.NodeType); </span><span>string</span> sql = <span>string</span>.Format(<span>"</span><span>select * from {0} where {1}</span><span>"</span>, <span>typeof</span>(T).Name, left + oper +<span> right); Console.WriteLine(sql); </span><span>return</span> <span>null</span>;<span>//</span><span>将结果返回</span> <span> } </span><span>//</span><span>解析一般的条件,例如x=>x.name==xxxx x.age==xxx</span> <span>public</span> <span>static</span> <span>string</span><span> ResovleFunc(Expression express) { </span><span>var</span> inner = express <span>as</span><span> BinaryExpression; </span><span>string</span> Name = (inner.Left <span>as</span><span> MemberExpression).Member.Name; </span><span>object</span> Value = (inner.Right <span>as</span><span> ConstantExpression).Value; </span><span>var</span> Operator =<span> GetOperator(inner.NodeType); </span><span>string</span> Result = <span>string</span>.Format(<span>"</span><span>({0} {1} '{2}')</span><span>"</span><span>, Name, Operator, Value); </span><span>return</span><span> Result; } </span><span>//</span><span>解析linq to object这类扩展方法</span> <span>public</span> <span>static</span> <span>string</span><span> ResovleLinqToObject(Expression expression) { </span><span>var</span> MethodCall = expression <span>as</span><span> MethodCallExpression; </span><span>var</span> MethodName =<span> MethodCall.Method.Name; </span><span>if</span> (MethodName == <span>"</span><span>Contains</span><span>"</span><span>) { </span><span>object</span> Temp_Vale = (MethodCall.Arguments[<span>0</span>] <span>as</span><span> ConstantExpression).Value; </span><span>string</span> Value = <span>string</span>.Format(<span>"</span><span>%{0}%</span><span>"</span><span>, Temp_Vale); </span><span>string</span> Name = (MethodCall.Object <span>as</span><span> MemberExpression).Member.Name; </span><span>string</span> Result = <span>string</span>.Format(<span>"</span><span>{0} like '{1}'</span><span>"</span><span>, Name, Value); </span><span>return</span><span> Result; } </span><span>return</span> <span>null</span><span>; } </span><span>public</span> <span>static</span> <span>string</span><span> GetOperator(ExpressionType expressiontype) { </span><span>switch</span><span> (expressiontype) { </span><span>case</span><span> ExpressionType.And: </span><span>return</span> <span>"</span><span>and</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.AndAlso: </span><span>return</span> <span>"</span><span>and</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.Or: </span><span>return</span> <span>"</span><span>or</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.OrElse: </span><span>return</span> <span>"</span><span>or</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.Equal: </span><span>return</span> <span>"</span><span>=</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.NotEqual: </span><span>return</span> <span>"</span><span><></span><span>"</span><span>; </span><span>case</span><span> ExpressionType.LessThan: </span><span>return</span> <span>"</span><span><</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.LessThanOrEqual: </span><span>return</span> <span>"</span><span><=</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.GreaterThan: </span><span>return</span> <span>"</span><span>></span><span>"</span><span>; </span><span>case</span><span> ExpressionType.GreaterThanOrEqual: </span><span>return</span> <span>"</span><span>>=</span><span>"</span><span>; </span><span>default</span><span>: </span><span>throw</span> <span>new</span> Exception(<span>string</span>.Format(<span>"</span><span>不支持{0}此种运算符查找!</span><span>"</span> +<span> expressiontype)); } } }</span>
已经初步的达到了我们的目的了,但是我们的查询条件不可能固定是2个,有可能是N个,这时左边和右边又要继续再分下去,直到无法再分(想到递归了吧?)。而且我们还需要将查询条件参数化。而且我们的条件删除时也会用到。所以我们应该把它独立出来。传入一个lambda,生成sql where部分的语句,生成sqlparameter[]。这才是关键。。于是我们来构建一个解析Expresstion的类。。下面我就直接给出我自己写的实现代码了。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 <span>public</span> <span>class</span><span> ResolveExpress { </span><span>public</span> Dictionary<<span>string</span>, <span>object</span>><span> Argument; </span><span>public</span> <span>string</span><span> SqlWhere; </span><span>public</span><span> SqlParameter[] Paras; </span><span>///</span> <span><summary></span> <span>///</span><span> 解析lamdba,生成Sql查询条件 </span><span>///</span> <span></summary></span> <span>///</span> <span><param name="expression"></param></span> <span>///</span> <span><returns></returns></span> <span>public</span> <span>void</span><span> ResolveExpression(Expression expression) { </span><span>this</span>.Argument = <span>new</span> Dictionary<<span>string</span>, <span>object</span>><span>(); </span><span>this</span>.SqlWhere =<span> Resolve(expression); </span><span>this</span>.Paras = Argument.Select(x => <span>new</span><span> SqlParameter(x.Key, x.Value)).ToArray(); } </span><span>private</span> <span>string</span><span> Resolve(Expression expression) { </span><span>if</span> (expression <span>is</span><span> LambdaExpression) { LambdaExpression lambda </span>= expression <span>as</span><span> LambdaExpression; expression </span>=<span> lambda.Body; </span><span>return</span><span> Resolve(expression); } </span><span>if</span> (expression <span>is</span><span> BinaryExpression) { BinaryExpression binary </span>= expression <span>as</span><span> BinaryExpression; </span><span>if</span> (binary.Left <span>is</span> MemberExpression && binary.Right <span>is</span> ConstantExpression)<span>//</span><span>解析x=>x.Name=="123" x.Age==123这类</span> <span>return</span><span> ResolveFunc(binary.Left, binary.Right, binary.NodeType); </span><span>if</span> (binary.Left <span>is</span> MethodCallExpression && binary.Right <span>is</span> ConstantExpression)<span>//</span><span>解析x=>x.Name.Contains("xxx")==false这类的</span> <span> { </span><span>object</span> value = (binary.Right <span>as</span><span> ConstantExpression).Value; </span><span>return</span><span> ResolveLinqToObject(binary.Left, value, binary.NodeType); } </span><span>if</span> (binary.Left <span>is</span> MemberExpression && binary.Right <span>is</span> MemberExpression)<span>//</span><span>解析x=>x.Date==DateTime.Now这种</span> <span> { LambdaExpression lambda </span>=<span> Expression.Lambda(binary.Right); Delegate fn </span>=<span> lambda.Compile(); ConstantExpression value </span>= Expression.Constant(fn.DynamicInvoke(<span>null</span><span>), binary.Right.Type); </span><span>return</span><span> ResolveFunc(binary.Left, value, binary.NodeType); } } </span><span>if</span> (expression <span>is</span><span> UnaryExpression) { UnaryExpression unary </span>= expression <span>as</span><span> UnaryExpression; </span><span>if</span> (unary.Operand <span>is</span> MethodCallExpression)<span>//</span><span>解析!x=>x.Name.Contains("xxx")或!array.Contains(x.Name)这类</span> <span>return</span> ResolveLinqToObject(unary.Operand, <span>false</span><span>); </span><span>if</span> (unary.Operand <span>is</span> MemberExpression && unary.NodeType == ExpressionType.Not)<span>//</span><span>解析x=>!x.isDeletion这样的 </span> <span> { ConstantExpression constant </span>= Expression.Constant(<span>false</span><span>); </span><span>return</span><span> ResolveFunc(unary.Operand, constant, ExpressionType.Equal); } } </span><span>if</span> (expression <span>is</span> MemberExpression && expression.NodeType == ExpressionType.MemberAccess)<span>//</span><span>解析x=>x.isDeletion这样的 </span> <span> { MemberExpression member </span>= expression <span>as</span><span> MemberExpression; ConstantExpression constant </span>= Expression.Constant(<span>true</span><span>); </span><span>return</span><span> ResolveFunc(member, constant, ExpressionType.Equal); } </span><span>if</span> (expression <span>is</span> MethodCallExpression)<span>//</span><span>x=>x.Name.Contains("xxx")或array.Contains(x.Name)这类</span> <span> { MethodCallExpression methodcall </span>= expression <span>as</span><span> MethodCallExpression; </span><span>return</span> ResolveLinqToObject(methodcall, <span>true</span><span>); } </span><span>var</span> body = expression <span>as</span><span> BinaryExpression; </span><span>if</span> (body == <span>null</span><span>) </span><span>throw</span> <span>new</span> Exception(<span>"</span><span>无法解析</span><span>"</span> +<span> expression); </span><span>var</span> Operator =<span> GetOperator(body.NodeType); </span><span>var</span> Left =<span> Resolve(body.Left); </span><span>var</span> Right =<span> Resolve(body.Right); </span><span>string</span> Result = <span>string</span>.Format(<span>"</span><span>({0} {1} {2})</span><span>"</span><span>, Left, Operator, Right); </span><span>return</span><span> Result; } </span><span>///</span> <span><summary></span> <span>///</span><span> 根据条件生成对应的sql查询操作符 </span><span>///</span> <span></summary></span> <span>///</span> <span><param name="expressiontype"></param></span> <span>///</span> <span><returns></returns></span> <span>private</span> <span>string</span><span> GetOperator(ExpressionType expressiontype) { </span><span>switch</span><span> (expressiontype) { </span><span>case</span><span> ExpressionType.And: </span><span>return</span> <span>"</span><span>and</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.AndAlso: </span><span>return</span> <span>"</span><span>and</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.Or: </span><span>return</span> <span>"</span><span>or</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.OrElse: </span><span>return</span> <span>"</span><span>or</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.Equal: </span><span>return</span> <span>"</span><span>=</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.NotEqual: </span><span>return</span> <span>"</span><span><></span><span>"</span><span>; </span><span>case</span><span> ExpressionType.LessThan: </span><span>return</span> <span>"</span><span><</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.LessThanOrEqual: </span><span>return</span> <span>"</span><span><=</span><span>"</span><span>; </span><span>case</span><span> ExpressionType.GreaterThan: </span><span>return</span> <span>"</span><span>></span><span>"</span><span>; </span><span>case</span><span> ExpressionType.GreaterThanOrEqual: </span><span>return</span> <span>"</span><span>>=</span><span>"</span><span>; </span><span>default</span><span>: </span><span>throw</span> <span>new</span> Exception(<span>string</span>.Format(<span>"</span><span>不支持{0}此种运算符查找!</span><span>"</span> +<span> expressiontype)); } } </span><span>private</span> <span>string</span><span> ResolveFunc(Expression left, Expression right, ExpressionType expressiontype) { </span><span>var</span> Name = (left <span>as</span><span> MemberExpression).Member.Name; </span><span>var</span> Value = (right <span>as</span><span> ConstantExpression).Value; </span><span>var</span> Operator =<span> GetOperator(expressiontype); </span><span>string</span> CompName =<span> SetArgument(Name, Value.ToString()); </span><span>string</span> Result = <span>string</span>.Format(<span>"</span><span>({0} {1} {2})</span><span>"</span><span>, Name, Operator, CompName); </span><span>return</span><span> Result; } </span><span>private</span> <span>string</span> ResolveLinqToObject(Expression expression, <span>object</span> value, ExpressionType? expressiontype = <span>null</span><span>) { </span><span>var</span> MethodCall = expression <span>as</span><span> MethodCallExpression; </span><span>var</span> MethodName =<span> MethodCall.Method.Name; </span><span>switch</span> (MethodName)<span>//</span><span>这里其实还可以改成反射调用,不用写switch</span> <span> { </span><span>case</span> <span>"</span><span>Contains</span><span>"</span><span>: </span><span>if</span> (MethodCall.Object != <span>null</span><span>) </span><span>return</span><span> Like(MethodCall); </span><span>return</span><span> In(MethodCall, value); </span><span>case</span> <span>"</span><span>Count</span><span>"</span><span>: </span><span>return</span><span> Len(MethodCall, value, expressiontype.Value); </span><span>case</span> <span>"</span><span>LongCount</span><span>"</span><span>: </span><span>return</span><span> Len(MethodCall, value, expressiontype.Value); </span><span>default</span><span>: </span><span>throw</span> <span>new</span> Exception(<span>string</span>.Format(<span>"</span><span>不支持{0}方法的查找!</span><span>"</span><span>, MethodName)); } } </span><span>private</span> <span>string</span> SetArgument(<span>string</span> name, <span>string</span><span> value) { name </span>= <span>"</span><span>@</span><span>"</span> +<span> name; </span><span>string</span> temp =<span> name; </span><span>while</span><span> (Argument.ContainsKey(temp)) { </span><span>int</span> code =<span> Guid.NewGuid().GetHashCode(); </span><span>if</span> (code < <span>0</span><span>) code </span>*= -<span>1</span><span>; temp </span>= name +<span> code; } Argument[temp] </span>=<span> value; </span><span>return</span><span> temp; } </span><span>private</span> <span>string</span> In(MethodCallExpression expression, <span>object</span><span> isTrue) { </span><span>var</span> Argument1 = (expression.Arguments[<span>0</span>] <span>as</span> MemberExpression).Expression <span>as</span><span> ConstantExpression; </span><span>var</span> Argument2 = expression.Arguments[<span>1</span>] <span>as</span><span> MemberExpression; </span><span>var</span> Field_Array =<span> Argument1.Value.GetType().GetFields().First(); </span><span>object</span>[] Array = Field_Array.GetValue(Argument1.Value) <span>as</span> <span>object</span><span>[]; List</span><<span>string</span>> SetInPara = <span>new</span> List<<span>string</span>><span>(); </span><span>for</span> (<span>int</span> i = <span>0</span>; i < Array.Length; i++<span>) { </span><span>string</span> Name_para = <span>"</span><span>InParameter</span><span>"</span> +<span> i; </span><span>string</span> Value =<span> Array[i].ToString(); </span><span>string</span> Key =<span> SetArgument(Name_para, Value); SetInPara.Add(Key); } </span><span>string</span> Name =<span> Argument2.Member.Name; </span><span>string</span> Operator = Convert.ToBoolean(isTrue) ? <span>"</span><span>in</span><span>"</span> : <span>"</span><span> not in</span><span>"</span><span>; </span><span>string</span> CompName = <span>string</span>.Join(<span>"</span><span>,</span><span>"</span><span>, SetInPara); </span><span>string</span> Result = <span>string</span>.Format(<span>"</span><span>{0} {1} ({2})</span><span>"</span><span>, Name, Operator, CompName); </span><span>return</span><span> Result; } </span><span>private</span> <span>string</span><span> Like(MethodCallExpression expression) { </span><span>object</span> Temp_Vale = (expression.Arguments[<span>0</span>] <span>as</span><span> ConstantExpression).Value; </span><span>string</span> Value = <span>string</span>.Format(<span>"</span><span>%{0}%</span><span>"</span><span>, Temp_Vale); </span><span>string</span> Name = (expression.Object <span>as</span><span> MemberExpression).Member.Name; </span><span>string</span> CompName =<span> SetArgument(Name, Value); </span><span>string</span> Result = <span>string</span>.Format(<span>"</span><span>{0} like {1}</span><span>"</span><span>, Name, CompName); </span><span>return</span><span> Result; } </span><span>private</span> <span>string</span> Len(MethodCallExpression expression, <span>object</span><span> value, ExpressionType expressiontype) { </span><span>object</span> Name = (expression.Arguments[<span>0</span>] <span>as</span><span> MemberExpression).Member.Name; </span><span>string</span> Operator =<span> GetOperator(expressiontype); </span><span>string</span> CompName =<span> SetArgument(Name.ToString(), value.ToString()); </span><span>string</span> Result = <span>string</span>.Format(<span>"</span><span>len({0}){1}{2}</span><span>"</span><span>, Name, Operator, CompName); </span><span>return</span><span> Result; } }</span>
1 2 3 4 5 6 7 8 9 10 11 12 13 <span>static</span> <span>void</span> Main(<span>string</span><span>[] args) { </span><span>string</span>[] Names = { <span>"</span><span>Andy</span><span>"</span>, <span>"</span><span>Amy</span><span>"</span>, <span>"</span><span>Mike</span><span>"</span><span> }; Expression</span><Func<Staff, <span>bool</span>>> func = x => (!Names.Contains(x.Name) && (x.Name == <span>"</span><span>A</span><span>"</span> || x.Name.Count() > <span>5</span><span>)); ResolveExpress resolve </span>= <span>new</span><span> ResolveExpress(); resolve.ResolveExpression(func); Console.WriteLine(resolve.SqlWhere); </span><span>foreach</span> (<span>var</span> item <span>in</span><span> resolve.Paras) { Console.WriteLine(item.ParameterName </span>+ <span>"</span><span>:</span><span>"</span> +<span> item.Value); } Console.ReadKey(); }</span>
结果:
这里有几个重要的东西要给大家讲下
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<DateTime.Now;
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最复杂的莫非查询部分了,而依照我这思路走下去,我觉得是可以自己完成一个的。。
我刚开始写博客第二天,没想到这文章反响这么大。我承认有点重复造轮子,也非常不成熟,但我还是想通过自己的思考去构造属于自己的东西。
不知道大家有没看过头文字D,里头有个组织叫东堂垫,他们里面的人是拆掉ABS的。因为他们会长说,你要先学会不使用ABS进行刹车才知道ABS的真谛