最近在学习LINQ,就想着边学边总结,写文章记录下来。
linq 概念:
语言集成查询(LINQ),是在对象和数据之间建立一种对应的关系。可以通过访问内存的方式来访问数据。LINQ 相关的类库都
在System.Linq 命名空间下,该命名空间提供支持LINQ进行查询的类和接口。
其中主要的两个类和两个接口:
IEnumerable<T>接口:表示可以查询的 数据集合,一个查询通常是对一个集合中的元素逐个筛选,返回一个新的IEnumerable<T>
对象,用来保存查询结果。
IQueryable<T>:继承IEnumerable<T>接口,表示一个可以查询表达式的目录树。
IEnumerable类:通过对IEnumerable<T>提供拓展方法,实现LINQ标准查询运算符,包括,过滤,导航,排序,查询,连接,求和等操作。
IQueryable:通过对IQueryable<T>提供拓展方法,实现LINQ标准查询运算符。
LINQ查询:
LINQ最具突破性的优势在与将文本查询与对象操作完美结合,查询数据和操作对象一样的安全轻松。查询事LINQ 的核心概念之一。
LINQ查询的目的就是从指定数据源中查询到满足条件的数据元素。并且可以对查询结果进行排序过滤。
LINQ查询主要包括:
数据源:表示LINQ查询将从哪里查询数据。
目标数据:用来指定查询具体想要的数据。
筛选条件:筛选条件定义对数据源的过滤
附加操作:表示一些其他的操作,排序等。
LINQ查询表达式:
关键字:
from:指定要查询的数据源级范围变量,多个from 表示从多个数据源中查找数据。
select:指定查询要返回的目标数据,可以指定任何类型,也可以是匿名类型。
where :指定元素筛选条件,并列表示必须同时满足。
orderby:指定元素的排序。
group:指定元素的的分组字段。
join:指定多个数据源的连接方式。
LINQ使用:
1.使用from子句指定数据源:
每一个LINQ查询都以from子句开始,包括两个功能:
1.指定查询采用的数据源
2.定义一个本地变量,表示数据源中的单个元素。
例:from 本地元素 in 数据源;
2.使用select 子句指定数据源:
在LINQ查询中select 和from 是必备子句,LINQ表达式的查询必须以select 获取group结束。select 子句指定在指定查询时产生结果的数据集中元素类型。
3.使用where 子句筛选条件:
where 子句中的逻辑操作:
exp1 exp2 exp1&&exp2 exp1||exp2
真 真 真 真
真 假 假 真
假 真 假 真
假 假 假 假
提示: 在LINQ中l可以使用多个where并列查询,可以通过函数等方式来提供判断条件,当出现多个逻辑运算符的时候可以考虑使用多个where并列。
4.使用orderby子句进行排序:
在LINQ中,通过orderby 子句对查询结果进行排序,可进行升(ascending)/降(desending)排序,默认情况是升序。在LINQ中orderby子句可以指定多个,第一个为主排序,第二个为次排序,依次类推,子句与子句之间用逗号隔开。
提示:orderby和where子句不一样,当LINQ中出现多个orderby时,洗后一个orderdy有效,前面的无效。
5.使用group子句分组查询:
LINQ中使用group自己实现对查询结果分组操作,group 自己返回类型是IGrouping<TKey,TElement>的查询结果,IGrouping<TKey,TElement>可以看成一个HashTable 内部嵌套这一个List列表的数据结果,包括一个主要属性:key,类型为TKey,表示查询分组的关键字,通常使用两层foreach遍历IGrouping中所有元素,外层的foreach按照key遍历,内层按照对应的元素列表遍历。
提示:在案例中StuArray 是Ieunmerable<Student>类型,value8是Student类型,StuGrp是分组查询后的结果,类型是IGrouping<int,Student>,最后结果由select产生,是一个Ieunmerable<T>类型,它的元素为StuGrp,所以分组后的最终类型为Ieunmerable<IGrouping<int,Student>>。
6.用from子句进行复合查询:
使用单个from 查询是对一个数据源操作,在开发过程中往往是需要操作多个数据源的,所以就需要使用的from的复合查询,在LINQ中,有两种类型的复合查询:
一:对同一个数据源的元素嵌套操作,这种操作,通常数据源的元素包含一个可以作为数据源的属性,方法等。外层from是对数据源操作,内层from 是对元素中的数据源进行查询。
二:是在对个多个数据源进行查询,通常每个from子句都中一个数据源提取数据,通常包含where子句对数据源进行过滤。
7.使用join子句联接:
在LINQ中,可以通过join子句实现联接操作,join子句可以将来自不同序列,并且在对象模型中没有直接关系的元素相关联,唯一就是要求每个源中的的元素需要共享某个可一个进行比较一判断是否相等的值。在LINQ中实现join由三种方式:
一:内部联接:
二:分组联接:
三:左外部联接:
代码案例:
ANLI1:用select 子句来指定目标数据, 用where子句删选条件,用orderby 子句进行排序,用group子句进行分组,使用from子句复合查询,使用join子句联接。
准备工作:
1.建一个控制台程序,在项目中创建一个实体类文件夹,用于存放实体类。
2.在实体层创建一个学生类与成绩层
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LINQ.Entity
{
/// <summary>
/// 学生信息实体类
/// </summary>
class Student
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="name"></param>
/// <param name="sex"></param>
/// <param name="age"></param>
public Student(string name, string sex, uint age)
{
this.StuAge = age;
this.StuSex = sex;
this.StuName = name;
}
public Student(string name, string sex, uint age,List<LessonScore> LS)
{
this.StuAge = age;
this.StuSex = sex;
this.StuName = name;
this.Score = LS;
}
//姓名
public string StuName { get; set; }
//性别
public string StuSex { get; set; }
//年龄
public uint StuAge { get; set; }
//学生成绩单
public List<LessonScore> Score { get; set; }
/// <summary>
/// 重写Tostring 方法,按指定格式输出学生信息
/// </summary>
/// <returns></returns>
public override String ToString()
{
string str;
str = string.Format("{0}---{1}----{2}",this.StuName,this.StuAge,this.StuSex);
return str;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LINQ.Entity
{
/// <summary>
/// 学生成绩类
/// </summary>
class LessonScore
{
/// <summary>
/// 构造函数
/// </summary>
public LessonScore(string les,float scr) {
this.Lesson = les;
this.Score = scr;
}
public float Score { get; set; }
public string Lesson { get; set; }
/// <summary>
/// 重写Tostring 方法,按指定格式输出成绩单
/// </summary>
/// <returns></returns>
public override String ToString() {
string str ;
str=string.Format("{0}---{1}分",this.Lesson,this.Score);
return str;
}
}
}
3.测试运行:
找到主函数:代码如下:
using LINQ.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LINQ
{
class Program
{
static void Main(string[] args)
{
//创建学生数据表示数据源
Student[] StuArray = {
new Student("张三","男",25),
new Student("李四","男",24),
new Student("王五","男",21),
new Student("欧阳二花","男",22),
new Student("欧阳一花","男",23),
new Student("Tiom","男",18),
new Student("欧阳七花","男",32),
new Student("欧阳八花","男",45)
};
///用select 子句来指定目标数据///
//LINQ 查询返回数据源strArry中的所有元素
var Query1 = from value in strArry select value;
//打印查询到的结果
foreach(Student Item in Query1){
System.Console.WriteLine(Item);
}
结果:
//LINQ 查询Query2返回数据源strArry 中全部学生的姓名
var Query2 = from value2 in StuArray select value2.StuName;
//打印学生姓名
foreach(string item in Query2){
System.Console.WriteLine("学生姓名:{0}",item);
}
结果:
//查询Query3返回数据源源strArry中的学生姓名,年龄,名字长度
var Query3 = from value3 in StuArray select new { value3.StuName, value3.StuAge, value3.StuName.Length }; //以匿名对象的方式返回数据
//因为编码的时候没有办法表示匿名类型,所以在遍历的时候就采用var 可变变量自动判断类型
foreach(var Item in Query3){
System.Console.WriteLine(Item);
}
结果:
///用where子句删选条件///
//查询Query4返回数据源中学生年龄大于20的学生姓名
var Query4 = from value4 in StuArray where value4.StuAge > 20 select value4.StuName;
//打印查询结果
foreach(string Item in Query4){
System.Console.WriteLine(Item);
结果:
//查询Query5返回数据源中学生年龄在20-25之间的学生姓名,性别,年龄
var Query5 = from value5 in StuArray where (value5.StuAge > 20) && (value5.StuAge < 25) select value5;
//打印结果
foreach(Student Item in Query5){
System.Console.WriteLine(Item);
}
结果:
//查询Query5返回数据源中学生年龄大于25或者小于20的学生姓名,性别,年龄,姓名长度(匿名对象)
var Query6 = from value6 in StuArray where (value6.StuAge < 20) || (value6.StuAge > 25) select new {value6.StuName,value6.StuSex,value6.StuAge,value6.StuName.Length};
//打印结果
foreach(var Item in Query6){
System.Console.WriteLine(Item);
}
结果:
///用orderby 子句进行排序///
//多个orderby子句
//查询Query7返回的数据源中所有的元素,主要按学生姓名的字符数从大到小排序,次要按学生的年龄从小到大排序
var Query7= from value7 in StuArray orderby value7.StuName.Length descending,value7.StuAge ascending select value7;
//打印查询结果
foreach(Student Item in Query7){
System.Console.WriteLine(Item);
}
结果:
///用group子句进行分组///
//查询Query8返回的数据源中所有的元素,按照学生年龄分组,并根据年龄的将序排序
var Query8 = from value8 in StuArray group value8 by value8.StuAge into StuGrp orderby StuGrp.Key descending select StuGrp;
//打印结果:
//外层遍历学生年龄
foreach(var StuGrp in Query8){
System.Console.WriteLine("{0}岁学生:",StuGrp.Key);
//内层遍历学生信息
foreach(var value8 in StuGrp){
System.Console.WriteLine("\t{0}",value8);
}
}
结果:
///使用from子句复合查询///
//一个数据源多个from 查询
//创建数据源
//创建学生List集合表示数据源
List<Student> StuList = new List<Student>();
StuList.Add(new Student("张三", "男", 20, new List<LessonScore> { new LessonScore("语文",80.5f)}));
StuList.Add(new Student("李四", "男", 20, new List<LessonScore> { new LessonScore("数学",90.5f)}));
StuList.Add(new Student("欧阳一花", "女", 20, new List<LessonScore>
{
new LessonScore("数学", 90.5f),
new LessonScore("语文", 90.5f),
new LessonScore("英语", 90.5f),
new LessonScore("政治", 90.5f)
}
));
//查询Query9采用两个from 复合查询。第二个from子句在第一个from子句查询结果中再次查询
var Query9 = from Stu in StuList from scr in Stu.Score where scr.Score > 85 group new { Stu.StuName, scr } by Stu.StuName;
//打印查询结果
//外层打印姓名
foreach(var grp in Query9){
System.Console.WriteLine(grp.Key);
//内层打印学生信息
foreach(var item in grp){
System.Console.WriteLine("\t{0}",item);
}
}
结果:
//多个数据源多个from复合查询
//创建数据源
int[] intArray1 = { 5, 15, 25, 35, 45, 55 };
int[] intArray2 = { 10,20,30,40,50,60,70,80};
//查询数据源
//查询Query9从两个数据源中获取的数据(查询数据源intArray2能够整除intArray1数据源中的元素,分组显示)
var Query10 = from val1 in intArray1 from val2 in intArray2 where val2 % val1 == 0 group val2 by val1;
//打印结果
foreach (var grp in Query10) //先打印分组
{
System.Console.Write("{0}:",grp.Key);
foreach(var val in grp){ //在打印组内数据
System.Console.Write("{0},",val);
}
System.Console.WriteLine();
}
结果:
///使用join子句进行连接///
//内部联接
//查询Query11使用join子句内部联接从两个数据源获取数据
var Query11 = from N1 in intArray1 join N2 in intArray2 on N1 % 5 equals N2 % 15 select new { VAL1 = N1, VAL2 = N2 };
//打印结果:
foreach (var item in Query11)
{
System.Console.WriteLine(item);
}
结果:
//分组联接
//查询Query12使用join子句分组联接
var Query12 = from F1 in intArray1 join F2 in intArray2 on F1 % 5 equals F2 % 15 into valGrp select new { VAL1 = F1, VALGrp = valGrp };
//打印结果:
foreach (var obj in Query12)
{
System.Console.Write("{0}:",obj.VAL1);
foreach(var val in obj.VALGrp){
System.Console.Write("{0},",val);
}
System.Console.WriteLine();
}
结果:
System.Console.ReadLine();
}
}
}