.NET中数据访问方式(一):LINQ

语言集成查询(Language-Integrated Query),简称LINQ,.NET中的LINQ体系如下图所示:


 

在编程语言层次,LINQ对于不同的数据源提供了相同的查询语法,方便了程序员操作不同的数据源。

可查询类型

LINQ之所以能够使用相同的语法操作不同的数据源,是因为和LINQ直接打交道的是可查询类型而非数据源,在LINQ中,直接或间接实现了IEnumerable<T>接口的类型称为可查询类型, .NET中如:List<T>Dictionary<TKey,TValue>,数组(由CLR负责隐式实现IEnumerable<T>接口)等,实现了IEnumerable<T>接口。
IQueryable<out T>继承自IEnumerable<T>,是个标记接口。

可查询类型无需额外操作即可进行LINQ操作,若数据源在内存中不以可查询类型的形式存在,那么LINQ提供程序必须要先将数据源转换为可查询类型,如LINQ to XML将XML文件转换为可查询的XElement类型:
 XElement contacts = XElement.Load(@"c:\myContactList.xml"); 

LINQ 提供程序

LINQ提供程序(LINQ Provider)提供了对特定的数据源进行标准的LINQ操作及一些扩展操作(如:LINQ to XML),不同的LINQ提供程序对于一些相同名称的扩展方法会提供不同的实现方式。.NET中预定义的LINQ提供程序包括:LINQ to ObjectLINQ to XML (C#)LINQ to SQLLINQ to DataSetLINQ to Entities
LINQ to SQL不建议使用,用LINQ to Entities来替代。

LINQ查询包含三个步骤:

  1. 获取数据源
  2. 创建查询语句
  3. 执行查询

LINQ查询方式

  • LINQ 表达式(又称为查询表达式
    from关键字开头,select关键字结尾。

  • 扩展方法(又称为标准查询
    System.Linq.Enumerable类和System.Linq.Queryable类,分别针对IEnumerable<T>IQueryable<T>接口进行的扩展。.NET也提供了几个对IEnumerable和IQueryable接口进行操作的扩展方法,如: Cast<TResult>OfType<TResult>

  • LINQ 表达式和扩展方法混合使用

    (from e in Employees
    where e.Salary>8000
    select e).ToList()

LINQ表达式和扩展方法对比:

LINQ表达式和扩展方法在编译后的代码没有什么区别

  • 对于排序、分组、联合查询使用LINQ表达式更为方便
//以排序为例,使用年龄、姓名、邮箱进行排序,
//LINQ表达式中使用逗号分隔排序字段,而扩展方法则需要多次调用相应的扩展方法
var result= from e in Employees
            where e.Age>50 && e.Salary>8000
            orderby e.Age,e.Name,e.Email
            select e;

//等价的扩展方法
var result=Employees
           .Where(e=>e.Age>50 && e.Salary>8000)
           .OrderBy(e=>e.Age)
           .ThenBy(e=>e.Name)
           .ThenBy(e=>e.Email);
  • 扩展方法能够提供比LINQ表达式更复杂的查询
//取第26行到36行范围内的数据
var result=Employees.Skip(25).Take(10);

//使用LINQ表达式我表示写不出来......

LINQ表达式是对常用扩展方法在语法层面上的简化,LINQ表达式有着更好的可读性,在编译时LINQ表达式会被转化为对扩展方法的调用

LINQ查询特点:

  • 延迟查询
    若查询表达式的返回结果是IEnumerable<T>类型,则在声明查询表达式时不会执行查询,而是在迭代查询变量时才进行查询。贴一幅MSDN上的经典LINQ查询流程图(延迟查询):


     
  • 立即查询
    若查询表达式返回单个值或者使用了ToList<T>ToArray<T>等方法时会执行立即查询,因为这些操作会遍历数据。

一句话总结,若查询表达式不包含对数据源的遍历操作则执行延迟查询,否则会进行立即查询

LINQ表达式中的查询关键字

表格中的英文没什么难点,就不翻译了 :)

关键字描述
from Specifies a data source and a range variable (similar to an iteration variable).
where Filters source elements based on one or more Boolean expressions separated by logical AND and OR operators.
select Specifies the type and shape that the elements in the returned sequence will have when the query is executed.
group Groups query results according to a specified key value.
into Provides an identifier that can serve as a reference to the results of a join, group or select clause.
orderby Sorts query results in ascending or descending order based on the default comparer for the element type.
join Joins two data sources based on an equality comparison between two specified matching criteria.
let Introduces a range variable to store sub-expression results in a query expression.
in Contextual keyword in a join clause.
on Contextual keyword in a join clause.
equals Contextual keyword in a join clause.
by Contextual keyword in a group clause.
ascending Contextual keyword in an orderby clause.
descending Contextual keyword in an orderby clause.

两个接口

在LINQ中,一个查询表达式被编译为表达式树或者委托,查询结果为IEnumerable<T>类型则被编译为委托,查询结果是IQueryableIQueryable<T>类型则被编译为表达式树,在运行时表达式树会被解析为适合于数据源的查询语句。

  • System.Collection.Generic.IEnumerable<T>
    IEnumerable先将数据放到本地内存中,然后再执行过滤操作(如果有的话),适合于对当前进程中的数据进行查询操作,如:LINQ to XMLLINQ to Object
  • System.Linq.IQueryable<T>
    在执行查询操作时,IQueryable先在服务器端进行过滤操作(如果有的话),然后再将数据放到本地内存中。
    IQueryable适合使用对进程外(如数据库)的数据进行查询操作,如:LINQ to Entities

两个命名空间

System.Linq

System.Linq命名空间中包含用于LINQ查询的类和接口

System.Linq.Expressions

System.Linq.Expressions 命名空间包含了用于创建表达式树的类、 接口。

LINQ的优缺点

优点

  1. 对不同的数据源提供了几乎一致的查询操作,这可使我们更多的去关注业务逻辑而非对数据源的操作
  2. 提供编译期的类型检查
  3. 在书写LINQ查询表达式时可以使用Visual Studio的智能提示
  4. 调试方便

缺点

  1. 对于复杂的查询操作显得力不从心
  2. 容易写出性能不高的查询表达式

结语

本篇是自己学习LINQ的总结,不求面面俱到。通篇以文字叙述为主,辅以少量代码,若有错误希望大家指出。

工具推荐

LINQ Pad是一款轻量级的数据查询工具,在LINQ Pad中可以使用LINQ表达式、扩展方法、SQL语句等对数据库进行操作,简单易用功能强大。


书目推荐:

《LINQ Interview Questions Answers》

参考文章

Introduction to LINQ Queries (C#)
Standard Query Operators Overview (C#)
Query Expression Syntax for Standard Query Operators (C#)
Data Transformations with LINQ (C#)
LINQ provider basics
Enabling a Data Source for LINQ Querying
LINQ: Building an IQueryable Provider – Part I

版权声明

本文为作者原创,版权归作者雪飞鸿所有。 转载必须保留文章的完整性,且在页面明显位置处标明原文链接

如有问题, 请发送邮件和作者联系。

posted @ 2017-04-07 17:26  雪飞鸿  阅读(1543)  评论(0编辑  收藏  举报