LINQ驱动数据的查询功能
一、LINQ概念
LINQ是微软在.NetFramework3.5中新加入的语言功能,在语言中以程序代码方式处理集合的能力。
1.1 LINQ VS 循环处理
在我刚工作时候,对于集合对象的处理一般是采用循环这个集合处理,在处理实值类型上这样做效率还行,但是如果集合内是引用类型,使用LINQ就方便的多,例如一个程序要计算课程的总分和平均分,实体分别是Student和StudentScore
类的申明如下:
/// <summary>
/// 学生实体
/// </summary>
public class Student
{
/// <summary>
/// 学生主键
/// </summary>
public string StudentID { get; set; } /// <summary>
/// 学生名称
/// </summary>
public string StudentName { get; set;} }
/// <summary>
/// 学生分数实体
/// </summary>
public class StudentScore
{
/// <summary>
/// 学生分数主键
/// </summary>
public string ScoreId { get; set; } /// <summary>
///学生分数
/// </summary>
public int Score { get; set; }
}
使用循环方式实现统计本班总分和平均分代码如下:
List<Student> students = GetStudents();
List<StudentScore> CSScoreList = GetCSScores();
List<StudentScore> DBScoreList = GetDBScores(); double CSSum = 0.0, DBSum = 0.0;
//循环C#集合
foreach (StudentScore csScore in CSScoreList)
{
CSSum = CSSum + csScore.Score;
}
//循环DB集合
foreach (StudentScore dbScore in DBScoreList)
{
DBSum += dbScore.Score;
}
Console.WriteLine("本班的C#总分是:{0},平均分是:{1}", CSSum, CSSum/students.Count);
Console.WriteLine("本班的SQL总分是:{0},平均分是:{1}", DBSum, DBSum / students.Count);
Console.ReadKey();
使用Linq的代码处理如下
Console.WriteLine("本班的C#总分是:{0},平均分是:{1}", CSScoreList.Sum(t=>t.Score),CSScoreList.Average(t=>t.Score));
Console.WriteLine("本班的SQL总分是:{0},平均分是:{1}", DBScoreList.Sum(t => t.Score), DBScoreList.Average(t => t.Score));
使用LINQ中最简单的例子,说明LINQ给我们带来的便利。
二、LINQ的基础
LINQ本身以IEnumerable<T>两个接口为基础,IEnumerable<T>则负责泛型的集合,目前.NET Framework内的泛型集合类 System.Collection.Generic 命名空间都已实现 IEnumerable<T>,一般来说在.NET内的所有集合对象都能使用LINQ进行处理,如果不引用System.Linq命名空间,所有Linq功能都无法使用。
2.1 扩展方法
扩展方法赋予了程序设计语言可在现有类下扩展类的功能,且不需要修改原本程序代码。实现扩展方法十分简单,只需要建立一个静态类,名称建议用 "要扩展的类名称"+Extension字样,例如扩展Int的方法,就将类名命名为Int32Extension,接下来在类内加入要扩展的方法,但是要注意两件事:
1.必须是静态方法,且名称不能和现有的方法冲突
2.参数至少有一个,且类型为扩展类型,格式是"this[要扩展的类名称][参数名称]",若有两个以上的参数,则扩展类型放在第一个不能设置默认值。
/// <summary>
/// 定义INT32扩展类
/// </summary>
public static class Int32Extension
{
public static string FormartForMoney(this Int32 value)
{
return value.ToString("$###,###,###,##0");
}
} /// <summary>
/// 定义Double类型的拓展类
/// </summary>
public static class DoubleExtension
{
public static string FormartPercent(this double value)
{
return value.ToString("0.00%");
}
}
int money = ;
double d = 0.12345;
Console.WriteLine("{0}", money.FormartForMoney());
Console.WriteLine("{0}", d.FormartPercent());
Console.ReadKey();
2.2 匿名类型与对象初始化器
语法中有一个select new ,可以按所设置的属性自动产生类对象,并且自动赋予数值,这个语法包含了两个语言功能:对象初始化器与匿名类型。
对象初始化器:允许程序中通过声明方式直接给对象属性进行数值的初始化,而不必建立有参数的构造函数。(字典类型必须按照特定格式初始化)
匿名类型:不定义类的情况下生成新的类,Linq中常用。其中有几点限制:
(1) 匿名类型只在同一个函数内,如果要在其他函数共享必须动用Reflection或者是利用.NET4.0提供的动态类型机制。
(2) 匿名类型只能有属性,不可以有方法、事件、或字段等。
(3) 两个匿名类型对象的相等,必须要两个对象的属性值都相等才行。
(4) 匿名类型的初始化只能利用对象初始化器来进行,其属性生成后会变成只读。
2.3 类型推论
使用匿名类型在Linq中变量类型无法确定,如果试用IEnumerable<object>就失去强类型的好处,在.NET3.5中只要使用Linq并且以select new来产生结果的查询,其变量类型声明会使用var类型表示,var类型代表编译器腿短这个变量的类型,在LINQ中复杂查询如果是嵌套的错误率较高,所以用var替代。var的限制如下:
(1)使用var类型赋值语句时右边不能为null,否则编译器无法推断其类型。
(2)var类型只能用于局部变量的声明,不能用于全局变量,类层变量或者是函数的返回值。
(3)var类型不可用在匿名委派或者是方法群组中。
2.4 yield指令与延迟查询
微软提供了一个指令yield,它可以只传回每个元素的方式自动生成IEnumerable<T>对象
private static IEnumerable<int> GetYieldResult(IEnumerable<int> param)
{
foreach (var num in param)
{
if (num > )
{
yield break;
}
else
{
yield return num;
}
}
}
yield指令乍看之下只是精简写法,实际上这个方法的执行推迟到真正查询才触发,例如调用这个方法时候并不会执行,当执行ToList()时候才执行,这个机制称为延迟查询或者延迟执行。
三、Linq语句
Linq语句主要应用于集合的处理上, 这就是Linq的价值所在,而对于外部数据源,只要有相应的LINQ provider就一样享有Linq的完整功能。
通过例子学习LINQ是我的做法,例如以下就是求两个集合中相同存在的数字:
List<int> list1 = new List<int>() { , , , , , , };
List<int> list2 = new List<int>() { , , , , , };
var query = from item1 in list1 join item2 in list2 on item1 equals item2 select item1;
foreach (var q in query)
{
Console.WriteLine("{0}", q);
}
或者是查询目前某个订单的销售总数
var query=from o in orderList
group by o.ProductID into g
select new{ProductID=g.Key,Qty=g.sum(t=>t.ProductID)}
四、Linq函数
Where():查询结果过滤
Select():选取数据
SelectMany():相当于数据库的Cross Join,这个的查询结果是笛卡尔积,就是两个表数据的乘积,将表一所有数据和表二连接,通过例子:
IEnumerable<int> selectMany = list1.SelectMany(t=>list2).ToList(); 也可以写成 IEnumerable<int> selectMany = list1.SelectMany((int o) => { return list2; }).ToList(); selectMany()参数是Func<int,IEnumerable<TResult>>
GroupBy():本身具有延迟查询的特性:
List<int> groupList = new List<int>() { , , , , , , , , , , , , };
IEnumerable<IGrouping<int,int>> groupquery = groupList.GroupBy(t => t);
foreach (var group in groupquery)
{
Console.WriteLine("{0}的数量有{1}个", group.Key, group.Count());
}
ToLookup():和GroupBy()类似没有延迟加载,但是它会产生一个新的集合对象,这个集合对象由ILookup<TKey,TElement>所组成,允许多个键存在,一个键包含很多关联的实值例如:
var nameGroup = new[]
{
new {name="CallmeYhz",age=,group="A"},
new {name="周公瑾",age=,group="B"},
new {name="孔明",age=,group="A"},
new {name="郭奉孝",age=,group="C"},
new {name="孙仲谋",age=,group="B"},
new {name="子龙",age=,group="A"}
}; var ToLookUp = nameGroup.ToLookup(t => t.group);
foreach (var bigGroup in ToLookUp)
{
Console.WriteLine("当前是组{0}", bigGroup.Key);
foreach (var smallGroup in bigGroup)
{
Console.Write("名字是:{0},年龄是:{1}", smallGroup.name, smallGroup.age);
}
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
}
Join():
在linq语句中使用
List<int> list1 = new List<int>() { , , , , , };
List<int> list2 = new List<int>() { , , , , , };
var query = from item1 in list1
join item2 in list2 on item1 equals item2
select item1; query.ToList().ForEach(t => Console.Write("{0} ", t));
由此例子可知,它将原本的集合视为TOuter而将传入的集合视为TInner,而还要决定由哪个属性或者成员当Key。例子中list1为本身,注意顺序。
上面用linq函数实现则为:
List<int> list1 = new List<int>() { , , , , , };
List<int> list2 = new List<int>() { , , , , , };
var query = list1.Join(list2, a=>a, b=>b,(a,b)=>b);
query.ToList().ForEach(t => Console.Write("{0} ", t));
总结:目前常用的联接模式,Inner join由Enumerable<T>.Join()实现,CROSS JOIN 由Enumerable<T>SelectMany实现,还有一种Join模式没有考虑:LEFT OUTER JOIN 模式,要实现这个模式必须借助GroupJoin()。
GroupJoin():
List<int> list1 = new List<int>() { , , , , , };
List<int> list2 = new List<int>() { , , , , , , };
var query = list1.GroupJoin(
list2,
a => a,
b => b,
(a, b) => new { v = a, c = b.Count() }); query.ToList().ForEach(t => Console.WriteLine("找到list2中有{0}个{1}", t.c, t.v));
LINQ驱动数据的查询功能的更多相关文章
- linq 大数据 sql 查询及分页优化
前提: 需要nuget PredicateLib 0.0.5: SqlServer 2008R2 (建议安装 64 位): .net 4.5 或以上: 当前电脑配置: I7 4核 3.6G ...
- [.NET] SQL数据分页查询
[.NET] SQL数据分页查询 程序下载 范例下载:点此下载 原始码下载:点此下载 NuGet封装:点此下载 数据查询 开发系统时,使用C#执行SQL查询指令,就可以从SQL数据库里查询所需数据. ...
- linq根据传入数据集合查询对应子级数据
工作中经常用到的linq根据传入数据集合查询对应子级数据,整理共享,希望大家都能用得上,代码中doublesArray 为父节点对应ID数据集合,再根据ID数据集合查询全部子级数据. //获取缓存数据 ...
- linq依据传入数据集合查询相应子级数据
工作中经经常使用到的linq依据传入数据集合查询相应子级数据,整理共享,希望大家都能用得上,代码中doublesArray 为父节点相应ID数据集合,再依据ID数据集合查询所有子级数据. //获取缓存 ...
- 雷林鹏分享:jQuery EasyUI 数据网格 - 添加查询功能
jQuery EasyUI 数据网格 - 添加查询功能 本实例演示如何从数据库得到数据,并将它们显示在数据网格(datagrid)中.然后演示如何根据用户输入的搜索关键词搜寻显示结果. 创建数据网格( ...
- 创建ASP.NET Core MVC应用程序(5)-添加查询功能 & 新字段
创建ASP.NET Core MVC应用程序(5)-添加查询功能 & 新字段 添加查询功能 本文将实现通过Name查询用户信息. 首先更新GetAll方法以启用查询: public async ...
- SQL、Linq、lamda表达式 同一功能不同写法
一.SQL.Linq.lamda表达式 同一功能不同写法 SQL LINQ Lambda SELECT * FROM HumanResources.Employee from e in Employe ...
- solr6.1-----mysql 数据导入-查询
此部分一定要细心,lz 中间错了一个细节,调了好长时间(汗).请严格按照步骤操作 新建core 步骤1: 在webapps中solrhome下新建一个文件夹名字叫做collection1(名字不固定, ...
- ASP.NET MVC 学习4、Controller中添加SearchIndex页面,实现简单的查询功能
参考:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/examining-the-edit-method ...
随机推荐
- C++ string类的实现
c++中string类的实现 今天面试被考到了, 全给忘记了!!! //string类的实现 #include <iostream> #include <string.h> ...
- C语言猜拳游戏
2016年最后一篇文章 今天闲来无事Google了一段C语言写的猜拳游戏的代码(本人水平比较低,几乎是刚入门),我没做什么修改.这个switch语句里面对result的处理让我眼前一新,原来是这么玩的 ...
- java自带工具-jps、jinfo、jstack、jstat、jmap
掌握java自带的这些监控工具,有助与我们很好的分析问题和jvm性能调优秀.收集了些网上整理很好的文章. Java监控工具.调优.调试辅助函数 Java自带的GUI性能监控工具Jconsole以及Ji ...
- scala Basic 第三课
yield 在学习c#的时候学习过这个关键字,和这时的语义是一致的. 当你生成一个新的迭代器,而并不是想立刻使用,而是在其他地方使用的时候,可以延迟生成这个集合, 这时候yield关键字可以帮你完成这 ...
- [Django]模型提高部分--聚合(group by)和条件表达式+数据库函数
前言:本文以学习记录的形式发表出来,前段时间苦于照模型聚合中group by 找了很久,官方文章中没有很明确的说出group by,但在文档中有提到!!! 正文(最后编辑于2016-11-12): 聚 ...
- Url和Uri的区别
URL: URL是Uniform Resoure Locator(统一资源定位器)的缩写.就是WWW页的地址. 其URL地址格式排列为:scheme://host:Port/path其中 ·Inter ...
- 第7章 权限管理(1)_ACL权限
1. ACL权限 1.1 ACL权限简介与开启 (1)ACL权限简介 ①ACL是Access Control List的缩写,主要目的是在提供传统的owner,group,others的read,wr ...
- angular的跨域(angular百度下拉提示模拟)和angular选项卡
1.angular中$http的服务: $http.get(url,{params:{参数}}).success().error(); $http.post(url,{params:{参数}}).su ...
- angular学习笔记(二十九)-$q服务
angular中的$q是用来处理异步的(主要当然是http交互啦~). $q采用的是promise式的异步编程.什么是promise异步编程呢? 异步编程最重要的核心就是回调,因为有回调函数,所以才构 ...
- 3172: [Tjoi2013]单词
3172: [Tjoi2013]单词 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3246 Solved: 1565[Submit][Status ...