LINQ Operators之过滤(Filtering)

转: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。

时间: 2024-10-12 12:39:45

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

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

本篇继续LINQ Operators的介绍,这里要讨论的是LINQ中的排序和分组功能.LINQ的排序操作符有:OrderBy, OrderByDescending, ThenBy, 和ThenByDescending,他们返回input sequence的排序版本.分组操作符GroupBy把一个平展的输入sequence进行分组存放到输出sequence中. 排序/Ordering IEnumerable<TSource>→IOrderedEnumerable<TSource> O

过滤Filtering

过滤Filtering 注意 : 都是GenericAPIView或子类进行的操作 对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持. pip install django-filter 在配置文件中增加过滤后端的设置: #settings.pyINSTALLED_APPS = [ ... 'django_filters', # 需要注册应用, ] REST_FRAMEWORK = { ... 'DEFAULT_FILTER_BACKENDS':

LINQ之路10:LINQ to SQL 和 Entity Framework(下)

在本篇中,我们将接着上一篇“LINQ to SQL 和 Entity Framework(上)”的内容,继续使用LINQ to SQL和Entity Framework来实践“解释查询”,学习这些技术的关键特性.我们在此关注的是LINQ to SQL和Entity Framework中的”LINQ”部分,并会比较这两种技术的相同和不同之处.通过我们之前介绍的LINQ知识还有将来会讨论的更多LINQ Operators,相信阅者能针对LINQ to SQL和Entity Framework写出优雅

LINQ之路 9:LINQ to SQL 和 Entity Framework(上)

在上一篇中,我们从理论和概念上详细的了解了LINQ的第二种架构“解释查询”.在这接下来的二个篇章中,我们将使用LINQ to SQL和Entity Framework来实践“解释查询”,学习这些技术的关键特性.在本系列文章中,我不准备事无巨细的讨论LINQ to SQL和Entity Framework的方方面面,毕竟那样需要太多的篇幅,也会让我们从LINQ上面转移注意力,况且,园子里也有不少介绍LINQ to SQL和Entity Framework的好文章.我们在此关注的是LINQ to S

利用maven中resources插件的copy-resources目标进行资源copy和过滤

maven用可以利用如下配置进行资源过滤,pom.xml的配置如下: Xml代码   <build> <!-- 主资源目录 --> <resources> <resource> <!-- 设定主资源目录  --> <directory>src/main/resources</directory> <!-- maven default生命周期,process-resources阶段执行maven-resources-p

ASP.NET - LINQ 语言集成查询

LINQ(Language Integrated Query) LINQ语言集成查询是一组用于C#语言的扩展.它允许编写C#代码对数据集进行查询,这等同于使用数据库查询语句,这样程序员不必掌握数据库查询语句而是使用Linq就能完成相同的查询任务.而传统数据查询的弱点很多,比如执行简单查询也需要冗长的操作代码,查询语句是字符串格式,无法让编译器执行检查错误及早提示,查询不是强类型,查询参数容易写错,查询结果没有真正面向对象,每次查询取结果还得事先知道列名或列索引,不使用抽象工厂的前提下,查询语句是

Linq之旅:Linq入门详解(Linq to Objects)

示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集成查询).通过LINQ,我们可以使用相同API操作不同的数据源.接下来就让我们看看LINQ是什么以及如何使用? 再此之前,需要先了解的相关技术 1. 隐式类型.匿名类型.对象初始化器 1) 隐式类型,使用var关键字创建,C#编译器会根据用于初始化局部变量的初始值推断出变量的数据类型.(不过我个人认

[Hibernate Search] (5) 高级查询 - 过滤,投影和分面

高级查询 在介绍了更多的高级映射功能之后,是时候回顾一下之前介绍过的查询功能了,看看如何借助这些高级的映射功能来使用一些高级的查询功能.本文会通过以下几个方面进行介绍: 如何在不和数据库进行任何交互的前提下,借助Lucene的力量来动态的筛选结果 如何通过使用基于投影(Projection)的查询来获取需要的属性,从而避免与数据库的交互 如何使用分面搜索(Faceted Search)对搜索结果进行划分 如何使用查询时提升(Boosting) 如何给查询设置时间限制 过滤(Filtering)

委托、Linq学习

委托是一种类型,可以实例化. 常用泛型委托. new Predicate<T>(函数名) ,,必须要有一个输入参数,只能有一个参数,并且需要返回bool类型. new Action<T,T..>(函数名),可以有0-16个输入参数,不能有返回值. new Func<T,T...>(函数名),可以有0-16个输入参数,最后加一个参数标示返回的值的类型,必须有返回值. 匿名函数: var s1 = new Predicate<string>(delegate(s