0%

构建属于自己的ORM框架之二–IQueryable的奥秘 - Poiuyt_cyc - 博客园

Excerpt

上篇文章标题乱起,被吐槽了,这次学乖了。上篇文章中介绍了如何解析Expression生成对应的SQL语句,以及IQueryable的一些概念,以及我们所搭建的框架的思想等。但还没把它们结合并应用起来。这一篇文章将更黄更暴力,揭露IQueryable在实际使用中延迟加载的实现原理,结合上篇对Expre


上篇文章标题乱起,被吐槽了,这次学乖了。

上篇文章中介绍了如何解析Expression生成对应的SQL语句,以及IQueryable的一些概念,以及我们所搭建的框架的思想等。但还没把它们结合并应用起来。这一篇文章将更黄更暴力,揭露IQueryable在实际使用中延迟加载的实现原理,结合上篇对Expression的解析,我们来实现一个自己的“延迟加载”

如果还不太了解如何解析Expression和IQueryable的一些基本概念,可以先看看我的上篇文章

我们先来做些基本工作,定义一个IDataBase接口,里面可以定义些查询,删除,修改,新增等方法,为了节约时间,我们就定义一个查询和删除的方法,再定义一个获取IQueryable实例的方法

复制代码

1
2
3
4
5
6
   <span>public</span> <span>interface</span><span> IDataBase
{
List</span>&lt;T&gt; FindAs&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere);
</span><span>int</span> Remove&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere);
IQueryable</span>&lt;T&gt; Source&lt;T&gt;<span>();
}</span>

复制代码

再添加一个类DBSql,实现我们上面的IDataBase接口,这个类是负责提供对sql数据库的操作

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<span>public</span> <span>class</span><span> DBSql : IDataBase
{
</span><span>public</span> List&lt;T&gt; FindAs&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span> <span>int</span> Remove&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span> IQueryable&lt;T&gt; Source&lt;T&gt;<span>()
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}
}</span>

复制代码

IQueryable

上篇文章中有个朋友的回复对IQueryable的解释十分到位,“IQueryable只存贮条件,不立即运行,从而可以实现延迟加载。”那它是如何存贮条件,如何延迟加载的?

这时我们为了提供 public IQueryable Source() 所需的对象。我们再来建一个SqlQuery类,实现IQueryable

复制代码

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
   <span>public</span> <span>class</span> SqlQuery&lt;T&gt; : IQueryable&lt;T&gt;<span>
{
</span><span>public</span> IEnumerator&lt;T&gt;<span> GetEnumerator()
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span><span> Type ElementType
{
</span><span>get</span> { <span>throw</span> <span>new</span><span> NotImplementedException(); }
}

</span><span>public</span><span> Expression Expression
{
</span><span>get</span> { <span>throw</span> <span>new</span><span> NotImplementedException(); }
}

</span><span>public</span><span> IQueryProvider Provider
{
</span><span>get</span> { <span>throw</span> <span>new</span><span> NotImplementedException(); }
}
}</span>

复制代码

看到这里大家都不陌生吧?

GetEnumerator()是IEnumerable里的。有了它我们就能foreach了。有泛型和非泛型版本,所以有2个

Type提供访问当前对象的类型(反正由你定义。。。)

Expression是贮存查询条件的

IQueryProvider简单的翻译过来就是查询提供者,它是负责创建查询条件和执行查询的。我们写一个SqlProvider类来实现它

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<span>public</span> <span>class</span> SqlProvider&lt;T&gt;<span> : IQueryProvider
{

</span><span>public</span> IQueryable&lt;TElement&gt; CreateQuery&lt;TElement&gt;<span>(Expression expression)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span><span> IQueryable CreateQuery(Expression expression)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span> TResult Execute&lt;TResult&gt;<span>(Expression expression)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span> <span>object</span><span> Execute(Expression expression)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}
}</span>

复制代码

CreateQuery是创建查询条件。。

平时我们

IQueryable query=xxx源;

query=query.Where(x=>x.Name==”123”);

这时Where方法里做的其实就是将前面query的Expression属性和Where里的(x=>x.Name==”123”)相并,并且调用Provider属性里的CreateQuery方法。我们可以把我们的代码改成这样,来看看到底是不是这么回事。

复制代码

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
<span>public</span> <span>class</span><span> DBSql : IDataBase
{
</span><span>public</span> IQueryable&lt;T&gt; Source&lt;T&gt;<span>()
{
</span><span>return</span> <span>new</span> SqlQuery&lt;T&gt;<span>();
}

</span><span>public</span> List&lt;T&gt; FindAs&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span> <span>int</span> Remove&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}
}

</span><span>public</span> <span>class</span> SqlQuery&lt;T&gt; : IQueryable&lt;T&gt;<span>
{

</span><span>private</span><span> Expression _expression;
</span><span>private</span><span> IQueryProvider _provider;

</span><span>public</span><span> SqlQuery()
{
_provider </span>= <span>new</span> SqlProvider&lt;T&gt;<span>();
_expression </span>= Expression.Constant(<span>this</span><span>);
}

</span><span>public</span><span> SqlQuery(Expression expression, IQueryProvider provider)
{
_expression </span>=<span> expression;
_provider </span>=<span> provider;
}

</span><span>public</span> IEnumerator&lt;T&gt;<span> GetEnumerator()
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span><span> Type ElementType
{
</span><span>get</span> { <span>return</span> <span>typeof</span>(SqlQuery&lt;T&gt;<span>); }
}

</span><span>public</span><span> Expression Expression
{
</span><span>get</span> { <span>return</span><span> _expression; }
}

</span><span>public</span><span> IQueryProvider Provider
{
</span><span>get</span> { <span>return</span><span> _provider; }
}
}

</span><span>public</span> <span>class</span> SqlProvider&lt;T&gt;<span> : IQueryProvider
{
</span><span>public</span> IQueryable&lt;TElement&gt; CreateQuery&lt;TElement&gt;<span>(Expression expression)
{
IQueryable</span>&lt;TElement&gt; query = <span>new</span> SqlQuery&lt;TElement&gt;(expression, <span>this</span><span>);
</span><span>return</span><span> query;
}

</span><span>public</span><span> IQueryable CreateQuery(Expression expression)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span> TResult Execute&lt;TResult&gt;<span>(Expression expression)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span> <span>object</span><span> Execute(Expression expression)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}
}</span>

复制代码

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
     <span>public</span> <span>class</span><span> Staff
{
</span><span>public</span> <span>int</span> ID { <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> <span>string</span> Name { <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><span>static</span> <span>void</span> Main(<span>string</span><span>[] args)
{
IDataBase db </span>= <span>new</span><span> DBSql();
IQueryable</span>&lt;Staff&gt; query = db.Source&lt;Staff&gt;<span>();
</span><span>string</span> name = <span>"</span><span>张三</span><span>"</span><span>;
Expression express </span>= <span>null</span><span>;
query </span>= query.Where(x =&gt; x.Name == <span>"</span><span>赵建华</span><span>"</span><span>);
express </span>=<span> query.Expression;
query </span>= query.Where(x =&gt; x.Name ==<span> name);
express </span>=<span> query.Expression;
}</span>

复制代码

段点打在 

public IQueryable CreateQuery(Expression expression)

每次query.Where都会跑这里来。并且Expression都是前后相并的结果。

到了这一步,相信大家都明白了IQueryable只存贮条件这个概念了吧。

那延迟加载呢?什么时候加载啊!当我们foreach或者ToList/ToArray时啊。这时你想到了什么?GetEnumerator()。在调用GetEnumerator()时。我们再调用Provider里的Execute(Expression)。里面解析Expression,生成SQL语句,通过反射的方式生成实例,再一个个返回回去。完成!下面我直接给代码了。解析Expression的类我也改了,这个更黄更暴力。

复制代码

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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  <span>public</span> <span>class</span><span> ResolveExpression
{
</span><span>public</span> Dictionary&lt;<span>string</span>, <span>object</span>&gt;<span> Argument;
</span><span>public</span> <span>string</span><span> SqlWhere;
</span><span>public</span><span> SqlParameter[] Paras;
</span><span>private</span> <span>int</span> index = <span>0</span><span>;
</span><span>///</span> <span>&lt;summary&gt;</span>
<span>///</span><span> 解析lamdba,生成Sql查询条件
</span><span>///</span> <span>&lt;/summary&gt;</span>
<span>///</span> <span>&lt;param name="expression"&gt;&lt;/param&gt;</span>
<span>///</span> <span>&lt;returns&gt;&lt;/returns&gt;</span>
<span>public</span> <span>void</span><span> ResolveToSql(Expression expression)
{
</span><span>this</span>.index = <span>0</span><span>;
</span><span>this</span>.Argument = <span>new</span> Dictionary&lt;<span>string</span>, <span>object</span>&gt;<span>();
</span><span>this</span>.SqlWhere =<span> Resolve(expression);
</span><span>this</span>.Paras = Argument.Select(x =&gt; <span>new</span><span> SqlParameter(x.Key, x.Value)).ToArray();
}

</span><span>private</span> <span>object</span><span> GetValue(Expression expression)
{
</span><span>if</span> (expression <span>is</span><span> ConstantExpression)
</span><span>return</span> (expression <span>as</span><span> ConstantExpression).Value;
</span><span>if</span> (expression <span>is</span><span> UnaryExpression)
{
UnaryExpression unary </span>= expression <span>as</span><span> UnaryExpression;
LambdaExpression lambda </span>=<span> Expression.Lambda(unary.Operand);
Delegate fn </span>=<span> lambda.Compile();
</span><span>return</span> fn.DynamicInvoke(<span>null</span><span>);
}
</span><span>if</span> (expression <span>is</span><span> MemberExpression)
{
MemberExpression member </span>= expression <span>as</span><span> MemberExpression;
</span><span>string</span> name =<span> member.Member.Name;
</span><span>var</span> constant = member.Expression <span>as</span><span> ConstantExpression;
</span><span>if</span> (constant == <span>null</span><span>)
</span><span>throw</span> <span>new</span> Exception(<span>"</span><span>取值时发生异常</span><span>"</span> +<span> member);
</span><span>return</span> constant.Value.GetType().GetFields().First(x =&gt; x.Name ==<span> name).GetValue(constant.Value);
}
</span><span>throw</span> <span>new</span> Exception(<span>"</span><span>无法获取值</span><span>"</span> +<span> expression);
}

</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> BinaryExpression)<span>//</span><span>解析二元运算符</span>
<span> {
BinaryExpression binary </span>= expression <span>as</span><span> BinaryExpression;
</span><span>if</span> (binary.Left <span>is</span><span> MemberExpression)
{
</span><span>object</span> value =<span> GetValue(binary.Right);
</span><span>return</span><span> ResolveFunc(binary.Left, value, binary.NodeType);
}
</span><span>if</span> (binary.Left <span>is</span> MethodCallExpression &amp;&amp; (binary.Right <span>is</span> UnaryExpression || binary.Right <span>is</span><span> MemberExpression))
{
</span><span>object</span> value =<span> GetValue(binary.Right);
</span><span>return</span><span> ResolveLinqToObject(binary.Left, value, binary.NodeType);
}
}
</span><span>if</span> (expression <span>is</span> UnaryExpression)<span>//</span><span>解析一元运算符</span>
<span> {
UnaryExpression unary </span>= expression <span>as</span><span> UnaryExpression;
</span><span>if</span> (unary.Operand <span>is</span><span> MethodCallExpression)
{
</span><span>return</span> ResolveLinqToObject(unary.Operand, <span>false</span><span>);
}
</span><span>if</span> (unary.Operand <span>is</span><span> MemberExpression)
{
</span><span>return</span> ResolveFunc(unary.Operand, <span>false</span><span>, ExpressionType.Equal);
}
}
</span><span>if</span> (expression <span>is</span> MethodCallExpression)<span>//</span><span>解析扩展方法</span>
<span> {
</span><span>return</span> ResolveLinqToObject(expression, <span>true</span><span>);
}
</span><span>if</span> (expression <span>is</span> MemberExpression)<span>//</span><span>解析属性。。如x.Deletion</span>
<span> {
</span><span>return</span> ResolveFunc(expression, <span>true</span><span>, ExpressionType.Equal);
}
</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>&lt;summary&gt;</span>
<span>///</span><span> 根据条件生成对应的sql查询操作符
</span><span>///</span> <span>&lt;/summary&gt;</span>
<span>///</span> <span>&lt;param name="expressiontype"&gt;&lt;/param&gt;</span>
<span>///</span> <span>&lt;returns&gt;&lt;/returns&gt;</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>&lt;&gt;</span><span>"</span><span>;
</span><span>case</span><span> ExpressionType.LessThan:
</span><span>return</span> <span>"</span><span>&lt;</span><span>"</span><span>;
</span><span>case</span><span> ExpressionType.LessThanOrEqual:
</span><span>return</span> <span>"</span><span>&lt;=</span><span>"</span><span>;
</span><span>case</span><span> ExpressionType.GreaterThan:
</span><span>return</span> <span>"</span><span>&gt;</span><span>"</span><span>;
</span><span>case</span><span> ExpressionType.GreaterThanOrEqual:
</span><span>return</span> <span>"</span><span>&gt;=</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> ResolveFunc(Expression left, <span>object</span><span> value, ExpressionType expressiontype)
{
</span><span>string</span> Name = (left <span>as</span><span> MemberExpression).Member.Name;
</span><span>string</span> Operator =<span> GetOperator(expressiontype);
</span><span>string</span> Value =<span> value.ToString();
</span><span>string</span> CompName =<span> SetArgument(Name, Value);
</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))
{
temp </span>= name +<span> index;
index </span>= index + <span>1</span><span>;
}
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>];
</span><span>var</span> Argument2 = expression.Arguments[<span>1</span>] <span>as</span><span> MemberExpression;
</span><span>var</span> fieldValue =<span> GetValue(Argument1);
</span><span>object</span>[] array = fieldValue <span>as</span> <span>object</span><span>[];
List</span>&lt;<span>string</span>&gt; SetInPara = <span>new</span> List&lt;<span>string</span>&gt;<span>();
</span><span>for</span> (<span>int</span> i = <span>0</span>; i &lt; 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)
{
Expression argument </span>= expression.Arguments[<span>0</span><span>];
</span><span>object</span> Temp_Vale =<span> GetValue(argument);
</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
<span>  public</span> <span>interface</span><span> IDataBase
{
List</span>&lt;T&gt; FindAs&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere);
</span><span>int</span> Remove&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere);
IQueryable</span>&lt;T&gt; Source&lt;T&gt;<span>();
}</span>

复制代码

复制代码

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
<span>namespace</span><span> Data.DataBase
{
</span><span>public</span> <span>class</span><span> DBSql : IDataBase
{
</span><span>private</span> <span>readonly</span> <span>static</span> <span>string</span> ConnectionString = <span>@"</span><span>Data Source=.;Initial Catalog=btmmcms-Standard;Persist Security Info=True;User ID=sa;Password=sa;</span><span>"</span><span>;

</span><span>public</span> IQueryable&lt;T&gt; Source&lt;T&gt;<span>()
{
</span><span>return</span> <span>new</span> SqlQuery&lt;T&gt;<span>();
}

</span><span>public</span> List&lt;T&gt; FindAs&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere)
{
</span><span>using</span> (SqlConnection Conn = <span>new</span><span> SqlConnection(ConnectionString))
{
</span><span>using</span> (SqlCommand Command = <span>new</span><span> SqlCommand())
{
</span><span>try</span><span>
{
Command.Connection </span>=<span> Conn;
Conn.Open();
</span><span>string</span> sql = <span>string</span>.Format(<span>"</span><span>select * from {0}</span><span>"</span>, <span>typeof</span><span>(T).Name);
</span><span>if</span> (lambdawhere != <span>null</span><span>)
{
ResolveExpression resolve </span>= <span>new</span><span> ResolveExpression();
resolve.ResolveToSql(lambdawhere);
sql </span>= <span>string</span>.Format(<span>"</span><span>{0} where {1}</span><span>"</span><span>, sql, resolve.SqlWhere);
Command.Parameters.AddRange(resolve.Paras);
}
</span><span>//</span><span>为了测试,就在这里打印出sql语句了</span>
<span> Console.WriteLine(sql);
Command.CommandText </span>=<span> sql;
SqlDataReader dataReader </span>=<span> Command.ExecuteReader();
List</span>&lt;T&gt; ListEntity = <span>new</span> List&lt;T&gt;<span>();
</span><span>while</span><span> (dataReader.Read())
{
</span><span>var</span> constructor = <span>typeof</span>(T).GetConstructor(<span>new</span><span> Type[] { });
T Entity </span>= (T)constructor.Invoke(<span>null</span><span>);
</span><span>foreach</span> (<span>var</span> item <span>in</span><span> Entity.GetType().GetProperties())
{
</span><span>var</span> value =<span> dataReader[item.Name];
</span><span>if</span> (value == <span>null</span><span>)
</span><span>continue</span><span>;
</span><span>if</span> (value <span>is</span><span> DBNull)
value </span>= <span>null</span><span>;
item.SetValue(Entity, value, </span><span>null</span><span>);
}
ListEntity.Add(Entity);
}
</span><span>if</span> (ListEntity.Count == <span>0</span><span>)
</span><span>return</span> <span>null</span><span>;
</span><span>return</span><span> ListEntity;
}
</span><span>catch</span><span> (Exception ex)
{
</span><span>throw</span><span> ex;
}
</span><span>finally</span><span>
{
Conn.Close();
}
}
}
}

</span><span>public</span> <span>int</span> Remove&lt;T&gt;(Expression&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span> lambdawhere)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}
}

</span><span>public</span> <span>class</span> SqlQuery&lt;T&gt; : IQueryable&lt;T&gt;<span>
{

</span><span>private</span><span> Expression _expression;
</span><span>private</span><span> IQueryProvider _provider;

</span><span>public</span><span> SqlQuery()
{
_provider </span>= <span>new</span> SqlProvider&lt;T&gt;<span>();
_expression </span>= Expression.Constant(<span>this</span><span>);
}

</span><span>public</span><span> SqlQuery(Expression expression, IQueryProvider provider)
{
_expression </span>=<span> expression;
_provider </span>=<span> provider;
}

</span><span>public</span> IEnumerator&lt;T&gt;<span> GetEnumerator()
{
</span><span>var</span> result = _provider.Execute&lt;List&lt;T&gt;&gt;<span>(_expression);
</span><span>if</span> (result == <span>null</span><span>)
</span><span>yield</span> <span>break</span><span>;
</span><span>foreach</span> (<span>var</span> item <span>in</span><span> result)
{
</span><span>yield</span> <span>return</span><span> item;
}
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span><span> Type ElementType
{
</span><span>get</span> { <span>return</span> <span>typeof</span>(SqlQuery&lt;T&gt;<span>); }
}

</span><span>public</span><span> Expression Expression
{
</span><span>get</span> { <span>return</span><span> _expression; }
}

</span><span>public</span><span> IQueryProvider Provider
{
</span><span>get</span> { <span>return</span><span> _provider; }
}
}

</span><span>public</span> <span>class</span> SqlProvider&lt;T&gt;<span> : IQueryProvider
{

</span><span>public</span> IQueryable&lt;TElement&gt; CreateQuery&lt;TElement&gt;<span>(Expression expression)
{
IQueryable</span>&lt;TElement&gt; query = <span>new</span> SqlQuery&lt;TElement&gt;(expression, <span>this</span><span>);
</span><span>return</span><span> query;
}

</span><span>public</span><span> IQueryable CreateQuery(Expression expression)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}

</span><span>public</span> TResult Execute&lt;TResult&gt;<span>(Expression expression)
{
MethodCallExpression methodCall </span>= expression <span>as</span><span> MethodCallExpression;
Expression</span>&lt;Func&lt;T, <span>bool</span>&gt;&gt; result = <span>null</span><span>;
</span><span>while</span> (methodCall != <span>null</span><span>)
{
Expression method </span>= methodCall.Arguments[<span>0</span><span>];
Expression lambda </span>= methodCall.Arguments[<span>1</span><span>];
LambdaExpression right </span>= (lambda <span>as</span> UnaryExpression).Operand <span>as</span><span> LambdaExpression;
</span><span>if</span> (result == <span>null</span><span>)
{
result </span>= Expression.Lambda&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span>(right.Body, right.Parameters);
}
</span><span>else</span><span>
{
Expression left </span>= (result <span>as</span><span> LambdaExpression).Body;
Expression temp </span>=<span> Expression.And(right.Body, left);
result </span>= Expression.Lambda&lt;Func&lt;T, <span>bool</span>&gt;&gt;<span>(temp, result.Parameters);
}
methodCall </span>= method <span>as</span><span> MethodCallExpression;
}
</span><span>var</span> source = <span>new</span> DBSql().FindAs&lt;T&gt;<span>(result);
dynamic _temp </span>=<span> source;
TResult t </span>=<span> (TResult)_temp;
</span><span>return</span><span> t;
}

</span><span>public</span> <span>object</span><span> Execute(Expression expression)
{
</span><span>throw</span> <span>new</span><span> NotImplementedException();
}
}
}</span>

复制代码

搞定,这时可以改下数据库连接,连到自己的数据库,然后像下面这样,添加一个实体类(要与数据库表对应),就可以使用了

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<span>class</span><span> Program
{
</span><span>public</span> <span>class</span><span> Staff
{
</span><span>public</span> <span>int</span> ID { <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> <span>string</span> Name { <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><span>static</span> <span>void</span> Main(<span>string</span><span>[] args)
{
IDataBase db </span>= <span>new</span><span> DBSql();
IQueryable</span>&lt;Staff&gt; query = db.Source&lt;Staff&gt;<span>();
query </span>= query.Where(x =&gt; x.Name == <span>"</span><span>张三</span><span>"</span><span>);
</span><span>foreach</span> (<span>var</span> item <span>in</span><span> query)
{

}
}
}</span>

复制代码

是不是很简单?

虽然信息量有点大,但慢慢理清并消化,我相信会对你又很大帮助!