在上一篇中,我们做了基于linq to sql 的多条件组合查询,但通过监视数据库发现,这样做的成本比较高,每次都要取出全部的数据到内存进行筛选.如何从真正意义上做到延迟加载,即一次只从数据库中取我们需要的用到的那部分数据呢.通过研究,有了下面的方法:
首先,我们要新建一个静态类,用于存放多条件组合查询的各种组合,比如or,And这些等等.代码如下:
代码
1
using
System.Linq.Expressions;
2
3
public
static
class
PredicateExtensionses
4
{
5
public
static
Expression
<
Func
<
T,
bool
>>
True
<
T
>
() {
return
f
=>
true
; }
6
7
public
static
Expression
<
Func
<
T,
bool
>>
False
<
T
>
() {
return
f
=>
false
; }
8
9
public
static
Expression
<
Func
<
T,
bool
>>
Or
<
T
>
(
this
Expression
<
Func
<
T,
bool
>>
exp_flow, Expression
<
Func
<
T,
bool
>>
expression2)
10
{
11
12
var invokedExpression
=
System.Linq.Expressions.Expression.Invoke(expression2, exp_flow.Parameters.Cast
<
System.Linq.Expressions.Expression
>
());
13
14
return
System.Linq.Expressions.Expression.Lambda
<
Func
<
T,
bool
>>
(System.Linq.Expressions.Expression.Or(exp_flow.Body, invokedExpression), exp_flow.Parameters);
15
16
}
17
public
static
Expression
<
Func
<
T,
bool
>>
And
<
T
>
(
this
Expression
<
Func
<
T,
bool
>>
exp_flow, Expression
<
Func
<
T,
bool
>>
expression2)
18
{
19
20
var invokedExpression
=
System.Linq.Expressions.Expression.Invoke(expression2, exp_flow.Parameters.Cast
<
System.Linq.Expressions.Expression
>
());
21
22
return
System.Linq.Expressions.Expression.Lambda
<
Func
<
T,
bool
>>
(System.Linq.Expressions.Expression.And(exp_flow.Body, invokedExpression), exp_flow.Parameters);
23
24
}
25
26
}
第一步工作完成后,我们就可以从具体应用层面上来调用这种组合了,此处,我们仍以FeedBack表对象为例,表示层调用代码如下:
我仅列举核心代码,注意:PageNavigator1是我页面的分页控件.
分页代码:
代码
1
private
void
ListDataBind(
int
pageIndex)
2
{
3
int
rowCount
=
0
;
4
int
pageCount
=
0
;
5
int
pageSize
=
30
;
6
Expression
<
Func
<
FeedBack,
bool
>>
expr
=
PredicateExtensionses.True
<
FeedBack
>
();
7
GetCondition(
ref
expr);
8
var hs
=
from h
in
hm.AllFeedBacks.Where(expr) select h;//
延迟加载,数据库没有任何操作
9
if
(pageIndex
==
1
)//
如果是第一次取数据,需要获取符合条件的总记录条数
10
{
11
rowCount
=
hs.Count();//
数据库进行一次Count操作
12
}
13
else//之后的记录条数,从分页控件持久态的属性中获取,省去一次Count查询
14
{
15
rowCount
=
PageNavigator1.RecordCount;
16
}
17
pageCount
=
rowCount
>
pageSize
?
Convert.ToInt32((rowCount
-
1
)
/
pageSize)
+
1
:
1
;//
通用分页算法
18
if
(pageIndex
>
pageCount)
19
{
20
pageIndex
=
pageCount;
21
}
22
var pageData
=
hs.Skip(pageSize
*
(pageIndex
-
1
)).Take(pageSize);//
这里也是延迟加载,数据库此时不操作
23
FeedBackManageList.DataSource
=
pageData;//
这里才正式加载数据,仅仅向数据库发出请求30条记录SQL
24
FeedBackManageList.DataBind();
25
PageNavigator1.RecordCount
=
rowCount;//给分页控件一些数据
26
PageNavigator1.PageCount
=
pageCount;//给分页控件一些数据
27
PageNavigator1.PageIndex
=
pageIndex;//给分页控件一些数据
28
}
接下来是关键部分,组合条件,注意这里,我们用到了第一步中定义好的组合类:
代码
private
void
GetCondition(
ref
Expression
<
Func
<
FeedBack,
bool
>>
expr) {
int
isLock
=
Int32.Parse(ddlIsLock.SelectedValue);
if
(isLock
>
-
1
)
{
expr
=
expr.
And
(c
=>
(c.IsLock
==
isLock));//一次组合
}
string
keyword
=
tbxKeyword.Text.FilterInjectStr();
if
(
!
keyword.IsNullOrEmpty())
{
expr
=
expr.
And
(c
=>
(c.HotelName.IndexOf(keyword)
>
-
1
)); //二次组合
}
}
到此,我们已经完成了linq to Sql多条件组合查询,并且对数据库的请求做到最小化.
另外,要特别说明的是:对数据源的任何操作,最好用延迟加载,否则,将有可能加载全部数据,
例如,我们写这样的代码:List<FeedBack> fbs = hm.AllFeedBacks.Where(c=>c.Id > 1000).ToList();这样消耗将会非常严重!因为这里会将FeedBack表所有数据全部加载进来!所以,千万要慎用这种写法.
总结:微软的linq to sql给我们带来便利的同时,也埋下许多的隐患,比如给像我这样的偷懒者更多便利,但却不去思考,往往一不小心就加载了数据,造成了资源的浪费.在享受这些便利的同时,应注意适时地进行研究,以让它们更好地为我们服务.