转:http://www.cnblogs.com/lifepoem/archive/2011/11/16/2250676.html

在本系列博客前面的篇章中,已经对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实现

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。

LINQ Operators之过滤(Filtering)的更多相关文章

  1. LINQ之路11:LINQ Operators之过滤(Filtering)

    在本系列博客前面的篇章中,已经对LINQ的作用.C# 3.0为LINQ提供的新特性,还有几种典型的LINQ技术:LINQ to Objects.LINQ to SQL.Entity Framework ...

  2. LINQ之路16:LINQ Operators之集合运算符、Zip操作符、转换方法、生成器方法

    本篇将是关于LINQ Operators的最后一篇,包括:集合运算符(Set Operators).Zip操作符.转换方法(Conversion Methods).生成器方法(Generation M ...

  3. LINQ之路14:LINQ Operators之排序和分组(Ordering and Grouping)

    本篇继续LINQ Operators的介绍,这里要讨论的是LINQ中的排序和分组功能.LINQ的排序操作符有:OrderBy, OrderByDescending, ThenBy, 和ThenByDe ...

  4. LINQ之路12:LINQ Operators之数据转换(Projecting)

    本篇继续LINQ Operators的学习,这里我们讨论的是数据转换的两种方式:Select和SelectMany,看似简单常用的两种运算符,却也大有讲究.我们会在本篇详细介绍他们的使用方式和适用的场 ...

  5. LINQ之路15:LINQ Operators之元素运算符、集合方法、量词方法

    本篇继续LINQ Operators的介绍,包括元素运算符/Element Operators.集合方法/Aggregation.量词/Quantifiers Methods.元素运算符从一个sequ ...

  6. 感受一下.net中用 lambda与 linq 做数据集过滤的不同

    lambda: ids.Add( _hahahacontext .hahahamodel .FirstOrDefault( a => //lambda做过滤 a.name == "张宏 ...

  7. LINQ之路13:LINQ Operators之连接(Joining)

    Joining IEnumerable<TOuter>, IEnumerable<TInner>→IEnumerable<TResult> Operator 说明 ...

  8. variant的过滤 | filtering and prioritizing genetic variants

    WGS和WES测序和分析会产生大量的variant数据. 显然直接分析全部的variant是非常不靠谱的. 做疾病的话,有一些常用的过滤套路. variant作用于基因表达主要分两大类: 1. cod ...

  9. LINQ LINQ Operators and Lambda Expression - Syntax & Examples

    LINQ is a cool feature in C# 3.0. Most of the developers are struggling for the syntax and examples. ...

随机推荐

  1. LOOPS(HDU 3853)

    LOOPS Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others)Total Sub ...

  2. 137. Single Number II——问题是查找,本质是hash查找,只是记录的是32 bit中各个位出现次数而已

    Given an array of integers, every element appears three times except for one. Find that single one. ...

  3. toggleClass() 方法做类似于微信扣扣点击语音图标按钮变成切换到语音输入功能,点击键盘图标按钮切换到文字输入状态的效果

    就是这种效果的类似. <html><head><script type="text/javascript" src="/jquery/jqu ...

  4. [转]JDK6和JDK7中的substring()方法

    substring(int beginIndex, int endIndex)在JDK6与JDK7中的实现方式不一样,理解他们的差异有助于更好的使用它们.为了简单起见,下面所说的substring() ...

  5. bzoj 2286: [Sdoi2011消耗战

    #include<cstdio> #include<iostream> #define M 1000009 #define N 250009 #define ll long l ...

  6. 在Linux中查看文件的编码及对文件进行编码转换

    如果你需要在Linux中操作windows下的文件,那么你可能会经常遇到文件编码转换的问题.Windows中默认的文件格式是GBK(gb2312),而Linux一般都是UTF-8.下面介绍一下,在Li ...

  7. C#如何以管理员身份运行程序

    在使用winform程序获取调用cmd命令提示符时,如果是win7以上的操作系统,会需要必须以管理员身份运行才会执行成功,否则无效果或提示错误. 比如在通过winform程序执行cmd命令时,某些情况 ...

  8. opencv实现图片缩放

    源码 #include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/imgproc/img ...

  9. Rhel6-mailsystem配置文档

    (postfix+dovecot+mysql+extmail) 理论基础:

  10. Android TextView多行垂直滚动

    在Android应用中,有时候需要TextView可以垂直滚动,今天我就介绍一下怎么实现的.在布局里: <TextView android:id="@+id/tvCWJ" a ...