1 LINQ TO Objects续(代码下载)
新建项目 linq_Ch2控制台程序,新建一个Entity文件夹
1.1 学生成绩查询(练习Join)
有三张表如下:学生表,班级表,成绩表。接下来我们按照这个在Entity文件夹建立3个实体类,类名跟表名一样。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace linq_Ch2.Entity
{ public class Student { /// <summary>
/// 学生编号
/// </summary>
public int StuId { get; set; } /// <summary>
/// 学生姓名
/// </summary>
public string StuName { get; set; } /// <summary>
/// 班级ID
/// </summary>
public int ClassId { get; set; } /// <summary>
/// 班级
/// </summary>
public Classroom Classrooms { get; set; }
} } |
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace linq_Ch2.Entity
{
public class Classroom
{
/// <summary>
/// 班级Id
/// </summary>
public int ClassId { get; set; }
/// <summary>
/// 班级名称
/// </summary>
public string ClassName { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace linq_Ch2.Entity
{
public class Score
{
/// <summary>
/// 分数Id
/// </summary>
public int ScoreId { get; set; }
/// <summary>
/// 学科名称
/// </summary>
public string ItemName { get; set; }
/// <summary>
/// 学生ID
/// </summary>
public int StuId { get; set; }
/// <summary>
/// 学生
/// </summary>
public Student Students { get; set; }
/// <summary>
/// 分数
/// </summary>
public double Scores { get; set; }
}
}
如上,3个实体类创建好了
①查询出 学生名 学科 分数 3列信息
首先我们初始化一点数据,在void main方法中写
1: List<Student> students = new List<Student> {
2: new Student{StuId=1,StuName="钱一",ClassId=1},
3: new Student{StuId=2,StuName="赵二",ClassId=1},
4: new Student{StuId=3,StuName="张三",ClassId=2},
5: new Student{StuId=4,StuName="李四",ClassId=1},
6: new Student{StuId=5,StuName="王五",ClassId=3},
7: new Student{StuId=6,StuName="陈六",ClassId=2},
8: new Student{StuId=7,StuName="田七",ClassId=3}
9: };
10: List<Score> scores = new List<Score> {
11: new Score{ScoreId=1,ItemName="语文",StuId=1,Scores=56},
12: new Score{ScoreId=2,ItemName="语文",StuId=2,Scores=65},
13: new Score{ScoreId=3,ItemName="语文",StuId=3,Scores=37},
14: new Score{ScoreId=4,ItemName="数学",StuId=1,Scores=33},
15: new Score{ScoreId=5,ItemName="数学",StuId=2,Scores=77},
16: new Score{ScoreId=6,ItemName="数学",StuId=3,Scores=84},
17: new Score{ScoreId=7,ItemName="英语",StuId=1,Scores=133},
18: new Score{ScoreId=8,ItemName="英语",StuId=2,Scores=53},
19: new Score{ScoreId=9,ItemName="英语",StuId=3,Scores=42},
20: new Score{ScoreId=10,ItemName="英语",StuId=4,Scores=33},
21: new Score{ScoreId=11,ItemName="数学",StuId=7,Scores=127}
22: };
23: List<Classroom> classrooms = new List<Classroom> {
24: new Classroom{ClassId=1,ClassName="高三(1)班"},
25: new Classroom{ClassId=2,ClassName="高三(2)班"},
26: new Classroom{ClassId=3,ClassName="高三(3)班"}
27: };
开始查询,用集合.Join(另一个集合,第一个集合的条件列,第二个集合的条件列,怎么处理(一个方法))
//学生名 学科 分数
var query1 = students.Join(
scores, //另一个集合
stu=>stu.StuId, //建立关系stu.StuId=sc.StuId
sc=>sc.StuId,
(s,sc)=>new { //选出要的数据
学生姓名=s.StuName,
学科=sc.ItemName,
分数=sc.Scores
}
);
Console.WriteLine("学生姓名\t学科\t\t分数");
foreach (var stu in query1)
{
Console.WriteLine(string.Format("{0}\t\t{1}\t\t{2}",stu.学生姓名,stu.学科,stu.分数));
}
效果图
第二种方式:
1: var query2 = from a in students
2: join b in scores
3: on a.StuId equals b.StuId
4: select new
5: {
6: 学生姓名 = a.StuName,
7: 学科 = b.ItemName,
8: 分数 = b.Scores
9: };
10:
11: Console.WriteLine("方式二");
12: Console.WriteLine("学生姓名\t学科\t\t分数");
13: foreach (var stu in query1)
14: {
15: Console.WriteLine(string.Format("{0}\t\t{1}\t\t{2}", stu.学生姓名, stu.学科, stu.分数));
16: }
②算学生的总分,查出 学生名 总分
1: // 学生名 总分(如果分数表找不到,就算0分)
2: var query3 = from c in query2
3: group c by c.学生姓名 into stuInfo
4: select new
5: {
6: 学生姓名 = stuInfo.Key,
7: 学生总分 = stuInfo.Sum(x => x.分数)
8: };
9: Console.WriteLine("求总分的案例");
10: Console.WriteLine("学生姓名\t总分");
11: foreach (var stu in query3)
12: {
13: Console.WriteLine(string.Format("{0}\t\t{1}", stu.学生姓名, stu.学生总分));
14: }
效果图:
③左查询(用join实现),DefaultIfEmpty后面括号中的参数是默认值,以students为主表,scores为副表,主表的信息全显示,副表只显示匹配学生Id相同的。
(如果分数表找不到,就算0分)
Console.WriteLine("左查询方式");
var query5 = from a in students
join b in scores
on a.StuId equals b.StuId
into pGroup
from pItem in pGroup.DefaultIfEmpty(new Score { Scores=0,ItemName="没参考",StuId=a.StuId,ScoreId=0})
select new
{
学生姓名 = a.StuName,
学科 = pItem.ItemName,
分数 = pItem.Scores
};
Console.WriteLine("学生姓名\t学科\t\t分数");
foreach (var stu in query5)
{
Console.WriteLine(string.Format("{0}\t\t{1}\t\t{2}", stu.学生姓名, stu.学科, stu.分数));
}
效果图:
如果是数据库,则等同于SQL语句
select s.StuId,s.StuName,s.ClassID,isnull(sc.ScoreId,0),isnull(sc.itemName,'没参考'),isnull(sc.stuID,0),isnull(sc.score,0) from dbo.Student s left join dbo.Score sc on s.StuID=sc.stuID
④交叉查询
效果图:
代码:
1:
2: Console.WriteLine("交叉查询方式");
3: var query6 = from a in students
4: from b in scores
5: select new
6: {
7: 学生姓名 = a.StuName,
8: 学科 = b.ItemName,
9: 分数 = b.Scores
10: };
11: Console.WriteLine("学生姓名\t学科\t\t分数");
12: foreach (var stu in query6)
13: {
14: Console.WriteLine(string.Format("{0}\t\t{1}\t\t{2}", stu.学生姓名, stu.学科, stu.分数));
15: }
等同于SQL:
select * from Student,Score
1.2 类型转换操作
①将数据源转换为IEnumerable<T>类型,使用AsEnumerable<T>方法
②将数据源转换为IQueryable<T>类型,使用AsQueryable<T>方法,用法同上
③将数据源转换成字典类型
代码如下:
//转换成Dictionary
Dictionary<int, Student> query9 = students.ToDictionary(i => i.StuId);
Console.WriteLine(query9[0].StuName);
④使用Enumerable类的Cast方法,该方法将非泛型的IEnumerable类型转换为泛型的IEnumerable<T>,至于转换成何种类型有Cast方法的TResult参数指定。
例如:
ArrayList arrList = new ArrayList();
for (int i = 0; i < 100; i++)
{
arrList.Add(i.ToString());
}
var query10 = from i in arrList.Cast<string>()
where i.IndexOf("0") > -1
select i;
foreach (var item in query10)
{
Console.Write(item+",");
}
Console.WriteLine();
效果图:
⑤使用 OfType<T> 筛选指定类型的元素
代码如下:
//OfType<T>
ArrayList arrList2 = new ArrayList();
arrList2.Add(1);
arrList2.Add("茗洋");
arrList2.Add("A");
arrList2.Add(3);
arrList2.Add("dd");
var query11=from item in arrList2.OfType<string>()
select item;
foreach (var item in query11)
{
Console.Write(item+",");
}
Console.WriteLine();
效果图:
⑥将数据源转换为List<T>类型,使用ToList<T>()方法,用法同IQueryable<T>
⑦将数据源转换为数组类型,使用ToArray()方法,用法同IQueryable<T>
⑧转换为一对多的字典Lookup<TKey,TSource>,与Dictionary区别就是 相同key会对应多个值
下面我们 把班级作为key列出来,然后列出班级里面的学生
var query12=from o in students
join c in classrooms
on o.ClassId equals c.ClassId
select new Student{
StuId=o.StuId,
StuName=o.StuName,
ClassId=o.ClassId,
Classrooms=new Classroom{
ClassId=c.ClassId,
ClassName=c.ClassName
}
};
ILookup<string, Student> query13 = query12.ToLookup(f => f.Classrooms.ClassName);
foreach (var item in query13)
{
Console.WriteLine(item.Key+"的学生如下");
foreach (var stu in item)
{
Console.Write(stu.StuName+",");
}
Console.WriteLine();
}
效果图如下
1.3 操作集合
1. 使用字符串的 EndsWith或者StartsWith过滤,使用CompareTo比较字符串的大小()
例如:找出以“张”开头的学生姓名
//StartWith
var query14 = from o in query2
where o.学生姓名.StartsWith("张")
select o;
foreach (var item in query14)
{
Console.Write(item.学生姓名+",");
}
Console.WriteLine();
效果图:
其中query2可以是 很多,例如List<T>,string[],IQueryable<T>等
2. 操作泛型作排序列表SortList<TKey,TValue>
SortList<TKey,TValue>表示按照键进行排序的键/值对的集合,键/值对是KeyValuePair<TKey,TValue>
1: //SortList
2: SortedList<int, Student> users = new SortedList<int, Student>
3: {
4: {2,new Student{StuId=2,StuName="钱一",ClassId=1}},
5: {12,new Student{StuId=12,StuName="赵二",ClassId=1}},
6: {1,new Student{StuId=1,StuName="张三",ClassId=2}},
7: };
8: Console.WriteLine("未按学生姓名排序前的结果如下:");
9: foreach (var item in users)
10: {
11: Console.Write(" 键"+item.Key + ":"+item.Value.StuName);
12: }
13: var query15 = from s in users
14: orderby s.Value.StuName descending
15: select s;
16: Console.WriteLine();
17: Console.WriteLine("按学生姓名排序后的结果如下:");
18: foreach (var item in query15)
19: {
20: Console.Write(" 键" + item.Key + ":" + item.Value.StuName);
21: }
效果图
3. 操作泛型双向链表LinkedList<T>
泛型双向列表LinkedList<T>表示由T指定类型的双向链表,它通过当前元素可以直接访问该元素的前一个或者后一个元素(如果不存在返回空),元素为LinkedListNode<T>类型
效果图:
代码:
1: Console.WriteLine();
2: //LinkedList
3: LinkedList<int> ints2 = new LinkedList<int>();
4: ints2.AddFirst(0);
5: for (int i = 1; i < 10; i++)
6: {
7: ints2.AddAfter(ints2.Find(i-1),i);
8: }
9: //使用Linq过滤,排序泛型双向链表
10: var query16 = from item in ints2
11: where item > 0 && item < 9
12: orderby item descending
13: select item;
14: //显示结果
15: foreach (var item in query16)
16: {
17: Console.Write(item.ToString()+",");
18: }
另一种方式:
1: Console.WriteLine();
2: var query17 = ints2.Where(x => x > 0 && x < 9).OrderByDescending(x => x);
3: //显示结果
4: foreach (var item in query16)
5: {
6: Console.Write(item.ToString() + ",");
7: }
4. 操作泛型队列Queue<T>
先进先出的线性表,使用Enqueue方法进行元素入队(添加)操作,使用Dequeue方法进行元素出队(删除)操作;使用Clear方法进行清空队列操作。Queue类没有实现IEnumerable<T>接口或IEnumerable接口,所以不能使用LINQ直接操作Queue类型的对象,可以使用Queue对象的Cast方法先把它转换为IEnumerable<T>类型,然后在使用LINQ对齐操作
Console.WriteLine();
Queue<Student> queues = new Queue<Student>();
queues.Enqueue(new Student { StuId=11,StuName="大一",ClassId=1});
queues.Enqueue(new Student { StuId = 2, StuName = "大二", ClassId = 1 });
queues.Enqueue(new Student { StuId = 34, StuName = "大三", ClassId = 2 });
queues.Enqueue(new Student { StuId = 4, StuName = "大四", ClassId = 1 });
var query18 = queues.OrderByDescending(x=>x.StuId);
//显示结果
foreach (var item in query18)
{
Console.Write(item.StuName + ",");
}
如果是Queue先转换成IEnumerable<T>,在LINQ操作
5. 操作泛型堆栈Stack<T>
后进先出的线性表,使用Push方法进行元素入栈(添加)操作,使用Dequeue方法进行元素出栈(删除)操作;使用Clear方法进行清空堆栈操作。Stack类没有实现IEnumerable<T>接口或IEnumerable接口,所以不能使用LINQ直接操作Queue类型的对象,可以使用Stack对象的Cast方法先把它转换为IEnumerable<T>类型,然后在使用LINQ对齐操作
代码:
Console.WriteLine();
Stack<Student> stacks = new Stack<Student>();
stacks.Push(new Student { StuId = 11, StuName = "大一", ClassId = 1 });
stacks.Push(new Student { StuId = 2, StuName = "大二", ClassId = 1 });
stacks.Push(new Student { StuId = 34, StuName = "大三", ClassId = 2 });
stacks.Push(new Student { StuId = 4, StuName = "大四", ClassId = 1 });
var query19 = from s in stacks
where s.ClassId != 1 || s.StuId!=2
select s;
//显示结果
foreach (var item in query19)
{
Console.Write(item.StuName + ",");
}
6. 操作泛型哈希集HashSet<T>
后泛型哈希集HashSet<T>是由T指定类型的基于集合的模型,泛型哈希集可以提供高性能的如并集,交集,补集等集合运算。泛型哈希集中的元素不能重复。泛型哈希集提供许多集合操作,如并集,交集,补集等。
代码:
1: /*HashSet*/
2: Console.WriteLine();
3: HashSet<Student> hashsets = new HashSet<Student> {
4: new Student{StuId=1,StuName="钱一",ClassId=1},
5: new Student{StuId=2,StuName="赵二",ClassId=1},
6: new Student{StuId=3,StuName="张三",ClassId=2},
7: new Student{StuId=4,StuName="李四",ClassId=1},
8: new Student{StuId=5,StuName="王五",ClassId=3},
9: new Student{StuId=6,StuName="陈六",ClassId=2},
10: new Student{StuId=7,StuName="田七",ClassId=3}
11: };
12: hashsets.Add(new Student { StuId = 11, StuName = "大一", ClassId = 1 });
13: //先按班级升序排序,再按姓名降序
14: var query20 = from s in hashsets
15: orderby s.ClassId ascending, s.StuName descending
16: select s;
17:
18: //显示结果
19: foreach (var item in query20)
20: {
21: Console.Write(item.StuName + ",");
22: }
7. 操作泛型字典Dictionary<TKey,TValue>
键不能重复,值可重复,键不会自动排序
代码:query9是一个Dictionary类型的
1: Console.WriteLine();
2: var query21 = from o in query9
3: where o.Value.StuName.CompareTo("张") > 0 //学生姓名大于“张”
4: orderby o.Key
5: select o;
6: foreach (var item in query21)
7: {
8: Console.WriteLine(item.Key + ":"+item.Value.StuName);
9: }
效果图:
8. 操作泛型排序字典SortedDictionary<TKey,TValue>
与Dictionary<TKey,TValue>的区别:泛型排序字典对添加的元素自动按键进行排序,代码例如:SortDictionary<int,Student> c=new SortDictionary<int,Student>{…….}
9. 操作泛型通用集合Collection<T>,跟List<T>一样用就行了
10. 操作泛型绑定列表 BindingList<T>
泛型绑定列表BindingList<T>能够提供支持数据绑定的泛型集合,他提供了IBindingList接口的具体泛型实现,可以用作创建双向数据绑定机制的积累,还可以通过AddNew方法支持创建实例
跟List<T>一样用就行了
关于还剩一点linq to objects明天写,顺便带点Linq to SQL