本系列博客前面的篇章中,已经对LINQ的作用、C# 3.0为LINQ提供的新特性,还有几种典型的LINQ技术:LINQ to Objects、LINQ to SQL、Entity Framework进行了比较详细的介绍,至此,我们应该了解了各种LINQ技术之间的联系和区别。千里之行始于足下,这些基础理论是理解和使用LINQ的关键。但是我们在前面的文章中对于LINQ查询运算符(LINQ Operators)并没有完整的介绍,这就是接下来这几篇博客中所要做的工作。大家可以按顺序依次对各个LINQ Operators进行学习,也可以把他们看成一个reference,作为参考查询之用。
示例数据
在这几篇讨论LINQ Operators的文章中,所有的示例都会(如果需要)用到下面的names数组:
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
所有查询数据库的示例都会假设我们创建了强类型的DataCotnext变量dataContext,如下:
var dataContext = new LifePoemContext ("connection string...");
...
public class LifePoemContext : DataContext
{
public LifePoemContext (string cxString) : base (cxString) {}
public Table<Customer> Customers { get { return GetTable<Customer>(); } }
public Table<Purchase> Purchases { get { return GetTable<Purchase>(); } }
}
[Table] public class Customer
{
[Column(IsPrimaryKey=true)] public int ID;
[Column] public string Name;
[Association (OtherKey="CustomerID")]
public EntitySet<Purchase> Purchases = new EntitySet<Purchase>();
}
[Table] public class Purchase
{
[Column(IsPrimaryKey=true)] public int ID;
[Column] public int? CustomerID;
[Column] public string Description;
[Column] public decimal Price;
EntityRef<Customer> custRef;
[Association (Storage="custRef",ThisKey="CustomerID",IsForeignKey=true)]
public Customer Customer
{
get { return custRef.Entity; } set { custRef.Entity = value; }
}
}
上面的DataContext和实体类是LINQ to SQL工具(如通过Visual Studio新增一个”LINQ to SQL Classes” Item)生成的简化版本。其中Customer和Purchase包含了一个简单的1:多关系,下面是对应的SQL表定义:
create table Customer
(
ID int not null primary key,
Name varchar(30) not null
)
create table Purchase
(
ID int not null primary key,
CustomerID int references Customer (ID),
Description varchar(30) not null,
Price decimal not null
)
Filtering Operators
IEnumerable<TSource> → IEnumerable<TSource>
返回输入sequence中元素的一个子集
Operator
|
说明
|
SQL语义
|
Where
|
返回符合给定条件的elements子集
|
WHERE
|
Take
|
返回开始的N个元素,忽略剩下的元素
|
WHERE ROW_NUMBER()...
或TOP n 子句
|
Skip
|
忽略开始的N歌元素,返回之后的元素
|
WHERE ROW_NUMBER()...
或NOT IN (SELECT TOP n...)
|
TakeWhile
|
返回输入sequence中的元素,直到指定条件为false,然后忽略剩下的元素
|
Exception thrown
|
SkipWhile
|
忽略输入sequence中的元素,直到指定条件为false,然后返回剩下的元素
|
Exception thrown
|
Distinct
|
返回去除重复元素的sequence
|
SELECT DISTINCT...
|
对每一个过滤方法而言,总是得到一个少于或等于初始元素个数的序列,而不可能返回更多的元素!并且这些元素不会经过任何改变,而是与原始元素一致。
Where
参数
|
类型
|
Source sequence
|
IEnumerable<TSource>
|
Predicate/条件
|
TSource => bool or (TSource,int) => boola
|
a带索引的lambda表达式在LINQ to SQL和Entity Framework中不可用。
查询表达式语法:where bool-expression
Enumerable.Where实现
The internal implementation of Enumerable.Where的内部实现大致如下(略去null引用的检查):
public static IEnumerable<TSource> Where<TSource>
(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource element in source)
if (predicate(element))
yield return element;
}
介绍
Where返回输入sequence中满足指定条件的elements,比如:
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IEnumerable<string> query = names.Where(name => name.EndsWith("y"));
// Result: { "Harry", "Mary", "Jay" }
对应的查询表达式语法:
IEnumerable<string> query = from n in names
where n.EndsWith("y")
select n;
在一个查询中where子句可以出现多次并且可以和let子句搭配使用:
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IEnumerable<string> query = from n in names
where n.Length > 3
let u = n.ToUpper()
where u.EndsWith("Y")
select u;
// Result: { "HARRY", "MARY" }
索引过滤
Where的条件支持第二个可选参数,类型为int,它的值等于每个element在输入sequence中的位置,这样我们就可以在lambda表达式中使用这个index信息。比如,下面的例子忽略index为单数的elements:
IEnumerable<string> query = names.Where((n, i) => i % 2 == 0);
// Result: { "Tom", "Harry", "Jay" }
如果你在LINQ to SQL或Entity Framework中使用索引参数,将会抛出异常。
LINQ to SQL和EF中的SQL LIKE 比较
下面这些字符串方法会被翻译成SQL的LIKE操作符:Contains、StartsWith、EndsWith。
比如:c.Name.Contains ("abc") 翻译成customer.Name LIKE '%abc%' (或者与之等价的参数版本)。
需要注意的是,在使用Contains时,我们只能用来与本地计算的表达式进行比较,如果要和另外一列进行比较,我们必须借助于SqlMethod.Like方法:
IQueryable<Purchase> query = purchases
.Where(p => SqlMethods.Like(p.Description, "%" + p.Customer.Name + "%"))
.OrderBy(p => p.ID)
.Select(p => p);
LINQ to SQL和EF中的WHERE x IN (..., ..., ...)
对于LINQ to SQL和EF,我们可以在过滤条件中对一个本地集合应用Contains方法,比如:
string[] chosenOnes = { "Tom", "Jay" };
IQueryable<Customer> query =
from c in dataContext.Customers
where chosenOnes.Contains(c.Name)
select c;
这会映射到SQL的IN操作符,即:WHERE customer.Name IN ("Tom", "Jay")。如果本地集合是一个entities数组或其他的非标量类型,LINQ to SQL和EF可能会生成EXISTS子句。
Take和Skips
参数
|
类型
|
Source sequence
|
IEnumerable<TSource>
|
获取或忽略的elements个数
|
int
|
Take返回前面n个元素并丢弃剩下的元素;Skip丢弃前面n个元素并返回剩下的元素。这两个方法通常一起使用以实现web页面的数据分页效果,让用户能在一个大型的结果集上进行导航,比如:
// 假设用户在一个图书数据库中查找包含"mercury"的所有图书
// 如果查找结果包含100条记录,下面的查询会返回前面20条
IQueryable<Book> query = dataContext.Books
.Where (b => b.Title.Contains ("mercury"))
.OrderBy (b => b.Title)
.Take (20);
// 下面的查询则返回第21到40行数据(第2页)
IQueryable<Book> query = dataContext.Books
.Where (b => b.Title.Contains ("mercury"))
.OrderBy (b => b.Title)
.Skip (20).Take (20);
对于SQL Server 2005,LINQ to SQL和EF 会把Take和Skip翻译成ROW_NUMBER函数,而对于更早的SQL Server版本,它们会被翻译成Top n子句。
TakeWhile和SkipWhile
参数
|
类型
|
Source sequence
|
IEnumerable<TSource>
|
Predicate
|
TSource => bool or (TSource,int) => bool
|
TakeWhile遍历输入sequence,返回每个element,直到给定的测试条件为false,然后忽略剩下的elements:
int[] numbers = { 3, 5, 2, 234, 4, 1 };
var takeWhileSmall = numbers.TakeWhile(n => n < 100); // { 3, 5, 2 }
SkipWhile遍历输入sequence,忽略每个element,直到给定的测试条件为false,然后返回剩下的elements:
int[] numbers = { 3, 5, 2, 234, 4, 1 };
var skipWhileSmall = numbers.SkipWhile(n => n < 100); // { 234, 4, 1 }
TakeWhile和SkipWhile没有对应的SQL翻译,如果在LINQ-to-db查询中使用他们会导致运行时错误。
Distinct
Distinct返回去除了重复元素之后的输入sequence,在确定元素是否重复时只能使用默认的相等比较方法:
// The following returns distinct letters in a string
char[] distinctLetters = "HelloWorld".Distinct().ToArray();
string s = new string (distinctLetters); // HeloWrd
我们可以在string变量上直接调用LINQ方法,因为string实现了IEnumerable<char>。
在下一篇博客中,会详细讨论LINQ运算符中的数据转换:Select和SelectMany。
<script type="text/javascript"></script>
分享到:
相关推荐
LINQ Operators Samples
LINQ - Restriction Operators This sample shows different uses of Restriction Operators. LINQ - Join Operators This sample shows different uses of Join Operators LINQ - Projection Operators ...
Demonstrating the overwhelming majority of LINQ operators and prototypes, it is a veritable treasury of LINQ examples. Rather than obscure the relevant LINQ principles in code examples by focusing ...
• Writing basic LINQ queries with C#: filtering, projecting, and sorting data from in-memory collections • Mastering advanced techniques for grouping and joining data and understanding the ...
Linq 之路
难得的学习LINQ的中文资料,很全很详细,包内包括两个文档: 一个是语言集成查询.pdf,内容简介如下: 1.LINQ 简介 简要介绍可编写的各种应用程序,以及使用 LINQ 查询可以解决的各种问题。 2.C# 中的 LINQ 入门 ...
vs2008语言集成查询(LINQ)之LINQ TO DataSet,dataset 数据表
Restriction Operators Projection Operators Partitioning Operators Join Operators Concatenation Operators Ordering Operators Grouping Operators Set Operators Conversion Operators Equality ...
LINQ to SQL语句(1)之Where LINQ to SQL语句(2)之Select/Distinct LINQ to SQL语句(3)之Count/Sum/Min/Max/Avg LINQ to SQL语句(4)之Join LINQ to SQL语句(5)之Order By LINQ to SQL语句(6)之Group By/Having LINQ ...
Restriction Operators, Aggregate Operators, Conversion Operators, Element Operators, Generation Operators, Grouping Operators, Join Operators, Miscellaneous Operators, Ordering Operators, Partitioning...
LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习LINQ学习
Linq开发宝典 LInq入门宝典 Linq To Xml linq to sql
LINQ初体验之LINQ to Object 1 一步一步学Linq to sql(一):预备知识 3 一步一步学Linq to sql(二):DataContext与实体 8 一步一步学Linq to sql(三):增删改 14 一步一步学Linq to sql(四):查询句法 20 ...
作为.NET上连接编程语言和数据库、内存对象、XML等各种类型数据之间的桥梁,LINQ引入了一种处理数据的全新理念,将查询无缝集成至开发语言之上。本书部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四...
linq基础 linq to sql linq基础 linq to sql
grouping, query continuations, and more Query syntax versus lambda syntax, and mixed syntax queries Composition and projection strategies for complex queries All of LINQ’s 40-plus query operators ...
C#\跟我一起学Visual.Studio.2008系列课程\跟我一起学Visual.Studio.2008系列课程(6):语言集成查询(LINQ)之LINQ.to.SQL.rar )
作为.NET上连接编程语言和数据库、内存对象、XML等各种类型数据之间的桥梁,LINQ引入了一种处理数据的全新理念,将查询无缝集成至开发语言之上。本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三...
\C#\跟我一起学Visual.Studio.2008系列课程\跟我一起学Visual.Studio.2008系列课程(7):语言集成查询(LINQ)之LINQ.to.XML入门篇.rar )
LINQ初体验之LINQ to Object 1 一步一步学Linq to sql(一):预备知识 4 一步一步学Linq to sql(二):DataContext与实体 9 一步一步学Linq to sql(三):增删改 15 一步一步学Linq to sql(四):查询句法 21 ...