IEnumeralbe<T>被误用一例

我一直使用Linq To SQL,以前一直没有问题,但前两天发生了一件怪事。先写个示例代码有助于理解。

 1  ///   <summary> 根据指定的参数和分页信息搜索文章,并输出分页情况。 </summary>
 2  ///   <param name="title"> 文章标题包含的内容。 </param>
 3  ///   <param name="keyword"> 文章关键字包含的内容。 </param>
 4  ///   <param name="pageIndex"> 从0开始的页码。 </param>
 5  ///   <param name="pageSize"> 每页包含的记录数。 </param>
 6  ///   <param name="pageCount"> 输出总页数。 </param>
 7  ///   <param name="total"> 输出匹配记录的总数目。 </param>
 8  ///   <return> 返回匹配文章的数组。 </return>
 9  public   static  Article[] QueryArticles( string  title,  string  keyword,  int  pageIndex,  int  pageSize,  out   int  pageCount,  out   int  total)
10  {
11       using  (FormusDataContext dc  =   new  ForumsDataContext())
12      {
13          Dictionary < string object >  args  =   new  Dictionary < string object > ();
14          args[ " Title " =  title;
15          args[ " Keyword " =  keyword;
16          var q  =  ParseQuery(args, dc.Articles);
17 
18          total  =  q.Count();
19          pageCount  =  ( int )Math.Ceiling(( double )total  /  ( double )pageSize);
20 
21          q  =  q.OrderByDescending(o  =>  o.PostTime).Skip(pageIndex  *  pageSize).Take(pageSize);
22           return  q.ToArray();
23      }
24  }
25 
26  //  根据参数字典生成查询。
27  private   static  IEnumerable < Article >  ParseQuery(Dictionary < string object >  args, IEnumerable<Article> source)
28  {
29      var q = source;
30 
31       if  (args.ContainsKey( " Title " ))
32      {
33           string  value  =  ( string )args[ " Title " ];
34          q  =  q.Where(o  =>  o.Title.Contains(value));
35      }
36 
37       if  (args.ContainsKey( " Keyword " ))
38      {
39           string  value  =  ( string )args[ " Keyword " ];
40           if  ( ! string .IsNullOrEmpty(keyword))
41          {
42              q  =  q.Where(o  =>  o.Keywords.Contains(value));
43          }
44      }
45 
46       //  解析其它参数
47 
48       return q;

49 } 

粗粗一看,这段程序并没有什么大问题,它的主要功能是提供了一个文章搜索的功能,通过指定文章的标题和关键字来检索数据。可在实际运行时,我发现如果提供了keyword这个参数时,程序就会在第18行抛出一个NullReferenceException,而错误是由Linq中的o.Keywords.Contains(value)引起的,因为Keywords这个字段在数据库里是可能有空值的。起始我很纳闷,q.Count()应该是由Linq To SQL生成一条SQL语句在数据库里执行,怎么会在C#的代码里出现这个错误呢。通过一番猜想和试验,我找到了问题的所在。 

罪魁祸首就是ParseQuery这个方法的参数和返回值使用了IEnumerable泛型类,这样整个查询连接起来就是一个混合体:
dc.Articles.Where(o => o.Keyword.Contains("...")).Count()
接下来会发生什么呢?很明显,整条语句的前半部分dc.Articles会通过Linq To  SQL来执行,它会把数据库中表的所有内容都读出来,剩下的一部分会通过Linq To Object来执行,仅仅对已生成的对象统计一个数量。而因为Linq To Object是在C#代码中执行的,就会发生之前所说的问题了。而即使不出现这样的错误,这种情况也是不能容忍的,因为每次执行都会把所有的数据都读出来,那个效率可想而知了。

要解决这个问题很简单,把ParseQuery方法的参数和返回值改成IQueryable<Article>就可以了。在此,也要提醒自己和广大的同行们,在使用扩展方法时应该注意,对于在有继承关系的类型上定义了相同名称和参数的扩展方法,必须准确的明白自己要调用的是哪个类型的扩展方法,而在调用时应该显式地将变量声明为相应的类型,而不应该随意地声明为某个父类型。

PS:以上代码是随手敲的,不保证代码可以通过编译。

转载于:https://www.cnblogs.com/effun/archive/2011/03/24/1993408.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值