`
datoplay
  • 浏览: 1611125 次
文章分类
社区版块
存档分类
最新评论

LINQ Operators之过滤(Filtering)

 
阅读更多

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

0
2
分享到:
评论

相关推荐

    LINQ Operators Samples

    LINQ Operators Samples

    Linq学习100例(含源代码)

    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 ...

    Pro LINQ: Language Integrated Query in C# 2010 (含源码)

    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 ...

    LINQ to Objects Using C# 4.0: Using and Extending LINQ to Objects and Parallel LINQ

    • 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用法

    Linq 之路

    LINQ中文版文档,LINQ 入门,LINQ 学习,LINQ编程指南

    难得的学习LINQ的中文资料,很全很详细,包内包括两个文档: 一个是语言集成查询.pdf,内容简介如下: 1.LINQ 简介 简要介绍可编写的各种应用程序,以及使用 LINQ 查询可以解决的各种问题。 2.C# 中的 LINQ 入门 ...

    vs2008语言集成查询(LINQ)之LINQ TO DataSet

    vs2008语言集成查询(LINQ)之LINQ TO DataSet,dataset 数据表

    linq_standard_query_operators

    Restriction Operators Projection Operators Partitioning Operators Join Operators Concatenation Operators Ordering Operators Grouping Operators Set Operators Conversion Operators Equality ...

    LINQ to SQL手册

    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 ...

    101 LINQ Samples.rar

    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学习LINQ学习LINQ学习

    LInq入门宝典 Linq To Xml linq to sql

    Linq开发宝典 LInq入门宝典 Linq To Xml linq to sql

    LINQ详细教程

    LINQ初体验之LINQ to Object 1 一步一步学Linq to sql(一):预备知识 3 一步一步学Linq to sql(二):DataContext与实体 8 一步一步学Linq to sql(三):增删改 14 一步一步学Linq to sql(四):查询句法 20 ...

    LINQ实战 linq to sql linq to xml 人民邮电出版社

    作为.NET上连接编程语言和数据库、内存对象、XML等各种类型数据之间的桥梁,LINQ引入了一种处理数据的全新理念,将查询无缝集成至开发语言之上。本书部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三、四...

    linq基础 linq to sql

    linq基础 linq to sql linq基础 linq to sql

    LINQ中文学习资料和LINQ 随身参考手册

    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 ...

    语言集成查询(LINQ)之LINQ.to.SQL

    C#\跟我一起学Visual.Studio.2008系列课程\跟我一起学Visual.Studio.2008系列课程(6):语言集成查询(LINQ)之LINQ.to.SQL.rar )

    LINQ 实战 7/11

    作为.NET上连接编程语言和数据库、内存对象、XML等各种类型数据之间的桥梁,LINQ引入了一种处理数据的全新理念,将查询无缝集成至开发语言之上。本书第一部分介绍了LINQ技术及C#和VB为此提供的新语言特性,第二、三...

    语言集成查询(LINQ)之LINQ.to.XML入门篇

    \C#\跟我一起学Visual.Studio.2008系列课程\跟我一起学Visual.Studio.2008系列课程(7):语言集成查询(LINQ)之LINQ.to.XML入门篇.rar )

    LINQ中文系列教程

    LINQ初体验之LINQ to Object 1 一步一步学Linq to sql(一):预备知识 4 一步一步学Linq to sql(二):DataContext与实体 9 一步一步学Linq to sql(三):增删改 15 一步一步学Linq to sql(四):查询句法 21 ...

Global site tag (gtag.js) - Google Analytics