• 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<stringobject> args = new Dictionary<stringobject>();
    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<stringobject> 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:以上代码是随手敲的,不保证代码可以通过编译。

  • 相关阅读:
    linux 切换图形界面
    google浏览器插件源码目录查询
    subline注册码
    mongodb数组多值查询(条件:数据库中必须包含条件信息)
    SpringBoot多数据源解决方案(转载)
    腾讯云服务器做代理
    多线程经典问题顺序打印
    flume 1.7在windows下的安装部署与测试运行
    解决spring-boot-maven-plugin插件打包,springboot启动时报找不到主main问题
    MYSQL的B+Tree索引树高度如何计算
  • 原文地址:https://www.cnblogs.com/effun/p/1993408.html
Copyright © 2020-2023  润新知