目录
Linq介绍
LINQ (读音link)------语言集成查询(Language Integrated Query),是.NET框架的扩展,一系列直接将查询功能集成到 C# 语言的技术统称,是一种使用类似SQL语句操作多种数据源的功能。
使用Linq,你可以从access数据库、程序对象的集合以及XML文档以及实现了IEnumerable或IEnumerable接口的集合类中查询数据。从.net framework3.5中开始引入,能够提升程序数据处理能力和开发效率,具有集成性、统一性、可扩展性、抽象性、说明式编程、可组成型、可转换性等优势。
Linq提供的程序
- Linq to Object。提供程序查询内存中的集合和数组。
- Linq to DataSet。提供程序查询ADO.NET数据集中的数据。
- Linq to SQL。提供程序查询和修改Sql Server数据库中的数据,将应用程序中的对象模型映射到数据库表。
- Linq to Entities。使用linq to entities时,会在后台将linq语句转换为sql语句与数据库交互,并能提供数据变化追踪。
- Linq to XML。提供程序查询和修改XML,既能修改内存中的xml,也可以修改从文件中加载的。
Linq查询
Linq查询包括两种方式:
一、语句查询,
二、方法查询。
语句查询使用较多,也更容易理解,微软官网推荐使用。
语句查询
查询语法:
cs
from 迭代变量 in 数据源 where .... select 迭代变量
cs
//查询遍历数组
//1.数据源
int[] nums = { 12, 34, 9, 45, 52, 99, 76, 120 };
//2.创建查询
var numQuery = from m in nums
select m;
//3.执行查询
foreach ( var m in numQuery)
{
Console.WriteLine(m);
}
查询表达式在循环访问查询变量时(如上述示例中foreach),才会执行。
select子句,基于查询结果返回需要的值或字段,并能够对返回值指定类型。
cs
List<ItemInfo> itemInfos = GetItemList();//获取所有的名目列表
//通过select返回列表中的所有名称属性值
var items=from item in itemInfos select item.ItemName;
foreach (var item in itemList01)
{
Console.WriteLine(item.Id+","+item.Name);
}
//通过select指定返回的类型
var itemList01 = from item in list
select new
{ //匿名类型
Id = item.ItemId,
Name = item.ItemName
};
foreach (var item in itemList01)
{
Console.WriteLine(item.Id+","+item.Name);
}
where子句:用来指定筛选的条件,与sql查询语句中的where功能一样。通过where子句获取到满足条件的结果.
cs
var itemList01 = from item in list
where item.ItemId>102
select item.ItemName;
foreach (var item in itemList02)
{
Console.WriteLine(item);
}
orderby:用来排序,与sql中orderby的功能相同,使得返回结果可以根据某字段或某种规则实现升序或降序排列。
linq中语句默认展示为升序,降序使用【orderby 表达式 descending】
cs
var itemList3 = from item in list
where item.ItemId > 102
orderby item.ItemId descending
select item.ItemName;
foreach (var item in itemList3)
{
Console.WriteLine(item);
}
group by子句:用来对查询结果进行分组。且未指定key的情况下,key取值默认是true和false。如果分为多组,获取数据结果时需要手动遍历key获取对应的value
cs
List<IncomeInfo> incomeList = new List<IncomeInfo>()
{
new IncomeInfo(){IncomeId=1,IncomeName="收入1",ItemId=101},
new IncomeInfo(){IncomeId=2,IncomeName="收入2",ItemId=101},
new IncomeInfo(){IncomeId=3,IncomeName="收入3",ItemId=103},
new IncomeInfo(){IncomeId=4,IncomeName="收入4",ItemId=102},
new IncomeInfo(){IncomeId=5,IncomeName="收入5",ItemId=103},
new IncomeInfo(){IncomeId=6,IncomeName="收入6",ItemId=104},
new IncomeInfo(){IncomeId=7,IncomeName="收入7",ItemId=102},
new IncomeInfo(){IncomeId=8,IncomeName="收入8",ItemId=105},
new IncomeInfo(){IncomeId=9,IncomeName="收入9",ItemId=104},
new IncomeInfo(){IncomeId=10,IncomeName="收入10",ItemId=106}
};
//把收入记录信息按ItemId分组
var incomeList1 = from income in incomeList group income by income.ItemId;
//分组打印
foreach(var income in incomeList1)
{
Console.WriteLine(income.Key);
foreach(var item in income)
{
Console.WriteLine(item.ItemId +"--"+item.IncomeName);
}
Console.WriteLine();
}
//输出结果:
101
101--收入1
101--收入2
103
103--收入3
103--收入5
102
102--收入4
102--收入7
104
104--收入6
104--收入9
105
105--收入8
106
106--收入10
Join子句:用于联合查询,一般会存在两个数据源,且两个数据源中有相同的字段可进行比较。使用格式为【join 数据 in 数据源1 on key1 equals key2】
cs
//inner join 只匹配能匹配上的
var incomeList2 = from item in list
join income in incomeList on item.ItemId equals income.ItemId
select new
{
ItemId = item.ItemId,
ItemName = item.ItemName,
IncomeId = income.IncomeId,
Income = income.IncomeName
};
foreach (var item in incomeList2)
{
Console.WriteLine($"名目编号:{item.ItemId}, 名目:{item.ItemName}, 收入编号:{item.IncomeId}, 收入名称:{item.Income}");
}
//left join 能左边为准,右边匹配不上的,就是null
var incomeList3= from income in incomeList
join item in list on income.ItemId equals item.ItemId
into ItemsNew
from newItem in ItemsNew.DefaultIfEmpty() //如果序列为空就为默认值
select new
{
IncomeId = income.IncomeId,
Income = income.IncomeName,
ItemName = newItem == null ? "无名目" : newItem.ItemName
};
foreach (var item in incomeList3)
{
Console.WriteLine($" 收入编号:{item.IncomeId}, 收入名称:{item.Income}, 名目:{item.ItemName}");
}
//输出:
收入编号:1, 收入名称:收入1, 名目:银行转账
收入编号:2, 收入名称:收入2, 名目:银行转账
收入编号:3, 收入名称:收入3, 名目:无名目
收入编号:4, 收入名称:收入4, 名目:股票收入
收入编号:5, 收入名称:收入5, 名目:无名目
收入编号:6, 收入名称:收入6, 名目:工资发放
收入编号:7, 收入名称:收入7, 名目:股票收入
收入编号:8, 收入名称:收入8, 名目:朋友还钱
收入编号:9, 收入名称:收入9, 名目:工资发放
收入编号:10, 收入名称:收入10, 名目:无名目
//right join 以右边为准,左边匹配不上的,就是null
var incomeList4 = from item in list
join income in incomeList on item.ItemId equals income.ItemId
into incomesNew //符合条件的收入列表
from newIncome in incomesNew.DefaultIfEmpty() //如果序列为空就为默认值
select new
{
IncomeId = newIncome == null ? 0 : newIncome.IncomeId,
Income = newIncome == null ? "无":newIncome.IncomeName,
ItemName = item.ItemName
};
foreach (var item in incomeList4)
{
Console.WriteLine($"名目:{item.ItemName} , 收入编号:{item.IncomeId}, 收入名称:{item.Income}");
}
收入编号:1, 收入名称:收入1,名目:银行转账
收入编号:2, 收入名称:收入2,名目:银行转账
收入编号:4, 收入名称:收入4,名目:股票收入
收入编号:7, 收入名称:收入7,名目:股票收入
收入编号:0, 收入名称:无, 名目:客户付款
收入编号:6, 收入名称:收入6,名目:工资发放
收入编号:9, 收入名称:收入9,名目:工资发放
收入编号:8, 收入名称:收入8,名目:朋友还钱
Linq扩展方法
Linq查询中,为了更加清晰明了的阅读,我们一般采用查询语法,但有些查询操作没有等效的查询表达式,只能采用方法查询,即调用内部方法,有些场景中也可以将查询语法和方法语法结合使用。

cs
int[] nums = { 12, 34, 9, 45, 52, 99, 76, 120 };
var queryList=from num in nums select num;
var avg=queryList.Average();//求平均
var max=queryList.Max();//求最大值
var min=queryList.Min();//求最小值
var newList=queryList.OrderBy(n=>n);
var numList1=nums.Where(num=>num>40);
var itemList4 = list.Where(item => item.ItemId > 103);
//链式写法 Where().OrderBy().Select()....
var itemList5 = list.Where(item => item.ItemId > 102).OrderByDescending(item=>item.ItemId).Select(item => new
{
Id = item.ItemId,
Name = item.ItemName
});
//Distinct/First/Find
var nums2= nums1.Distinct();//去重
ItemInfo item1=list.OrderBy(item=>item.ItemId).First();//返回第一个元素 若集合为空,会异常
ItemInfo item2 = list.OrderBy(item => item.ItemId).FirstOrDefault();//返回第一个元素 若集合为空,返回默认值
int maxId=list.Max(item=>item.ItemId);
int minId=list.Min(item=>item.ItemId);
int count = nums1.Distinct().Count();//获取集合总元素数
var itemList6 = list.Where(item => item.ItemId > 101);
var itemList7 = itemList6.Union(itemList4);//合并成一个集合,去重
var itemList8 = itemList6.Concat(itemList4);//合并成一个集合,不去重
var itemList9 = itemList6.Except(itemList4);//得到一个差集,去掉公共的部分
//Skip/Take 跳过指定数目的元素/连续取指定数目的元素
var itemList10 = list.Skip(2).Take(3);
//Join 连接两个集合,关联属性,合并一个集合,包含两个集合中的信息 inner join
var incomeList7 = list.Join(incomeList, item => item.ItemId, income => income.ItemId, (item, income) => new
{
ItemId = item.ItemId,
ItemName = item.ItemName,
Id = income.ItemId,
Income = income.IncomeName
});
foreach (var item in incomeList7)
{
Console.WriteLine($"名目编号:{item.ItemId}, 名目:{item.ItemName}, 收入编号:{item.Id}, 收入名称:{item.Income}");
}
//分组
var incomeList8 = incomeList.GroupBy(income => income.ItemId);
foreach(var item in incomeList8)
{
Console.WriteLine(item.Key);
foreach(var it in item)
{
Console.WriteLine(it.IncomeId + "," + it.IncomeName);
}
}
//GroupJoin ---等同性将两个序列的元素进行关联,并对结果进行分组。
var groups = list.GroupJoin(incomeList, item => item.ItemId, income => income.ItemId, (item, income) => new
{
ItemId = item.ItemId,
ItemName = item.ItemName,
Records = income.Select(r => new { Id = r.IncomeId, Income = r.IncomeName })
}) ;
foreach(var item in groups)
{
Console.WriteLine(item.ItemId+","+item.ItemName);
foreach(var r in item.Records)
{
Console.WriteLine("编号:"+r.Id+" , 名称:"+r.Income);
}
}