LINQ 基础

记住三个不等可能会对将来分析问题时有所帮助:

a、不是所有表示为关系的数据都能被计算机处理。

b、不是所有能被LINQ执行的查询都能被关系型数据库执行。

c、不是所有对象都是表示为关系的数据。

关系在.NET Framework中的表现形式。

微软在设计LINQ的时候,并没有为关系而造出一种新的类型。不过由关系的定义我们可以知道,关系就是一种集合,集合是一个抽象的概念,但是.NET Framework有一个最简单的集合访问器:IEnumerable接口(.NET中的所有集合访问器都从此接口继承)。所以,关系数据也可以用 IEnumerable来访问。同时,由上面的分析可知,任何一个关系都是某个类型的所有对象的集合。所以,关系就是一个强类型的集合,我们用IEnumerable<T>来在.NET Framework表示一个关系。

最后的几个容易混淆的点。

a、关系都是集合,集合不都是关系。

b、所有能被计算机处理的关系数据都能被IEnumerablt<T>来表示,但反之不然。当IEnumerable<T>表示的数据并非是一个关系数据时,LINQ查询就会出问题。

c、由于关系都是集合,所以对关系的某些查询与对集合的查询是相同的。但关系比集合能进行更多的查询操作(如连接)。

d、LINQ是面向关系型数据的,不是面向数据库中的表或者是我们所创造的一个数组,也不是面向IEnumerable<T>接口。

关于文中出现的一些概念的参考资料:

关系数据库,是建立在关系模型基础上的数据库,借助集合代数等数学概念和方法来处理数据库中的数据。现实世界中的各种实体以及实体之间的各种联系均用关系模型来表示。

关系模型的基本假定是所有数据都表示为数学上的关系,就是说n个集合的笛卡儿积的一个子集,有关这种数据的推理通过二值(就是说没有NULL)的谓词逻辑来进行, 这意味着对每个命题都没有两种可能的求值: 要么是真要么是假。数据通过关系演算和关系代数的一种方式来操作。

.NET Framework使用IEnumerable<T>表示一个关系(集合),但反之不然。

不过IEnumerable<T>的本质是一个序列枚举器,所以IEnumerable<T>本身就具备三重特性,集合、关系、序列。

.NET Framework定义了一个扩展类Enumerable用于对IEnumerable进行运算扩展,主要可以分为四部分:

一、查询/集合运算

1、集合运算

Intersect 交集运算

Union 并集运算

Except 差集运算

2、查询运算

Where 筛选

Select和SelectMany 投射

GroupBy 分组

Join和GroupJoin 连接

OrderBy、OrderByDescending、ThenBy和ThenByDescending 排序

3、集合谓词逻辑

Any

All

二、聚合运算

Aggregate 迭代聚合

Max 最大

Min 最小

Sum 求和

Average 平均值

Count和LongCount 计数

三、序列运算

Take和TakeWhile

Skip和SkipWhile

First和FirstOrDefault

Last和LastOrDefault

ElementAt和ElementAtOrDefault

Contact

Reverse

四、转换

OfType 按类型筛选

Distinct 去除重复值

ToArray

ToDictionary

ToList

ToLookup

对于LINQ而言,我们主要关注的是查询运算,即筛选、投射、分组、连接和排序。

LINQ为C#和VB两种语言都发明了一种叫做LINQ Expression的东西来辅助我们编写查询,避免去冗长的调用那些方法。在这里,我们简单的对C#所支持的LINQ Expression做一个介绍。

C#的LINQ Expression总是以一个from子句开始,from子句的格式与foreach的有些类似:

from element in set

from子句的最大作用在于定义元素与集合的关系用于后文使用,set是集合(IEnumerable<T>),element是集合元素(类型自动推导为T)。

只有from子句的LINQ Expression是不合法的。一个合法的LINQ Expression必须要有select子句或者group by子句(因为只有这两个子句才造成输出),下面对这两个子句作一简单介绍。

IEnumerable<string> result = from item in list select item.ToString();

这是一个完整的LINQ Expression,其用途为将list中的每一项(item)调用ToString方法,并将结果集合返回,所以这个LINQ Expression的返回类型就是IEnumerable<string>。select子句可以直接创建匿名对象,不过如果创建匿名对象,就必须用var来代替明确的返回类型。另外,LINQ Expression不是一个可以独立成为语句的表达式,所以下面的代码会是一个编译错误:

from item in list select item.ToString();

group by子句由两个关键字组成,group和by,语法如下:

group item by key

item 是需要被包括于分组中的项,而key则是分组依据。group by子句执行的操作是:对于集合中的每一个元素,检索其key的值,key值相同的元素的item组成一个集合,生成一个 IGrouping<TKey,TValue>类型的对象。这是一个包含一个key值(IGrouping.Key属性)和一个item集合(IGouping继承于IEnumerable<TValue>)的对象,每一个这样的对象对象表示一个key值的分组。而group by最终的结果为这些分组的集合,即group by操作的最终结果是一个类型为IEnumerable< IGrouping< key的类型, item的类型 > >的对象。

下面这个表达式用于数据分组(假设data是一个这样的类型:IEnumerable<Data>,而Data{ string Key, int Value }):

var result = from item in data group item by item.Key

但是这个result的结果是IEnumerable<IGrouping<string,Data>>

如果我们希望对分组后的Value进行求和(Sum),就必须对其再进行一次select:

var result2 = from item in result select new { Key = item.Key, Sum = item.Sum( dataItem => dataItem.Value ) };

//小说明,因为IGrouping<string,Data>继承于IEnumerable<Data>,所以这里的Sum方法其实正是Enumerable类中定义的扩展方法IEnumerable<Data>.Sum( Func<Data,int> selector )

这样的写法非常麻烦,而且也难看,所以C#提供了into关键字来帮助我们改善这种语法:

var result = from item in data group item by item.Key into groupItem select new { Key = groupItem.Key, Sum = groupItem.Sum( dataItem => dataItem .Value ) };

into的语法其实很简单,可以视为把from翻转过来。

set into element

只不过在这里set是一个LINQ表达式。但实际上from子句中的set也可以是一个表达式,LINQ Expression中绝大多数子句的参数都可以是一个表达式,一般而言只要类型匹配就可以使用。

最后,我们发现其实只有Value属性参与了统计,所以这个表达式还可以简化如下:

var result = from item in data group item.Value by item.Key into groupItem select new { Key = groupItem.Key, Sum = groupItem.Sum() };

关于orderby和join还有let子句在此略过

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值