这个星期章老师讲授了.Net开发的相关知识,如LINQ,XML,MVC等,因为我正在上数据库这门课,所以我今天就主要记录一下LINQ的学习。
首先介绍一下基础知识。
LINQ,语言集成查询(Language Integrated Query)是一组用于C#和Visual Basic语言的扩展。它允许编写C#或者Visual Basic代码以查询数据库相同的方式操作内存数据。
LINQ的关键词有:from, select, in, where, group by, orderby, …十分类似于SQL数据库,易于入门。
LINQ的写法:
(1) from 临时变量 in 实现IEnumerable<T>接口的对象
where条件表达式
[orderby 条件]
[group by 条件]
select 临时变量中被查询的值
(2) 实现IEnumerable<T>接口的对象.LINQ方法名(lambda表达式)。如:
string input = "hello world";
int count = input.Count(w=>w == ‘o‘); //查询字母o出现的次数
需要注意的是能够使用LINQ的对象需要实现IEnumerable<T>接口。并且LINQ的查询表达式是在最近一次创建对 象时才被编译的。
LINQ的命名空间(.NET Framework):System.Linq;
为了更好的学习LINQ,我们有必要了解隐匿类型,Lambda表达式以及IEnumerable 接口。
隐式类型,使用var关键字创建,C#编译器会根据用于初始化局部变量的初始值推断出变量的数据类型,var可代替任何类型。当我们无法确定自己将用的是什么类型,就可以使用var。代码示例如下:
1 var a = 1; //int a = 1; 2 var b = "123";//string b = "123"; 3 var myObj = new MyObj();//MyObj myObj = new MyObj()
上面的每行代码,与每行代码后面的注释,起到的作用是完全一样的。也就是说,在声明一个变量(并且同时给它赋值)的时候,完全不用指定变量的类型,只要一个var就解决问题了。而且这样写不会影响性能!
使用var定义变量时有以下四个特点:
1.必须在定义时初始化。也就是必须是var s = “abcd”形式,而不能是如下形式:
var s;
s = “abcd”;
2. 一但初始化完成,就不能再给变量赋与初始化值类型不同的值了。
3. var要求是局部变量。
Lambda表达式只是用更简单的方式来书写匿名方法,从而彻底简化.NET委托类型的使用。
Lambda表达式在C#中的写法是“arg-list => expr-body”,“=>”符号左边为表达式的参数列表,右边则是表达式体(body)。参数列表可以包含0到多个参数,参数之间使用逗号分割。
IEnumerable<T>泛型接口支持在制定数据集合上进行迭代操作。它定义了一组扩展方法,用来对数据集合中的元素进行遍历、过滤、排序、搜索等操作。我们每次针对集合类型编写foreach代码块,都是在使用迭代器。这些集合类型都实现了IEnumerable接口。迭代器的优点是,假设我们需要遍历一个庞大的集合只要集合中的某一个元素满足条件就完成了任务。
本次学习记录数据采用数据库实验课上老师所给数据,数据如下:
三张表
Sailors(int sid, string sname, int rating, int age),sid表示水手的编号,sname表示水手的姓名,rating表示水手的级别,age表示水手的年龄。
Boats(int bid,string bname,string color),其中bid表示船的编号,bname是船的名字,color是船的颜色。
Reserves(int sid, int bid, string rdate),Reserves中记录水手在哪天定了那只船,其中sid是指向Sailors的外关键字,bid是指向Boats的外关键字。
sailors 表
"22","dustin",7,45
"29","brustus",1,33
"31","lubber",8,56
"32","andy",8,26
"58","rusty",10,35
"64","horatio",7,35
"71","zorba",10,35
"74","horatio",9,35
"85","art",3,26
"86","john",1,17
"95","bob",3,64
"96","frodo",3,26
"98","tom",3,17
Boats 表
"101","A","red"
"102","B","green"
"103","C","blue"
"104","D","white"
"105","E","red"
"106","F","blue"
"107","G","green"
Reserves 表
"22","101","2010-01-08"
"22","102","2010-01-09"
"29","103","2010-01-09"
"31","102","2010-02-11"
"22","104","2010-03-08"
"22","103","2010-03-10"
"32","105","2010-03-11"
"32","106","2010-03-18"
"32","102","2010-03-19"
"58","104","2010-03-20"
"64","105","2010-03-20"
"95","101","2010-04-02"
"85","102","2010-04-05"
"22","101","2010-04-07"
"22","105","2010-05-01"
"22","106","2010-06-18"
"22","107","2010-07-09"
"31","106","2010-08-06"
"32","105","2010-08-06"
"29","104","2010-08-07"
"64","103","2010-09-05"
"58","102","2010-09-09"
"64","104","2010-11-03"
"64","105","2010-11-04"
"31","106","2010-12-06"
下面开始实践。
首先是表的属性创建,代码如下:
1 public class Sailors 2 { 3 public int sid { get; set; } 4 public string sname { get; set; } 5 public int rating { get; set; } 6 public int age { get; set; } 7 // Overrides the Object.ToString() to provide a 8 // string representation of the object properties. 9 public override string ToString() 10 { 11 return string.Format("{0} {1} {2} {3}", 12 sid, sname, rating, age); 13 } 14 } 15 16 public class Boats 17 { 18 public int bid { get; set; } 19 public string bname { get; set; } 20 public string color { get; set; } 21 // Overrides the Object.ToString() to provide a 22 // string representation of the object properties. 23 public override string ToString() 24 { 25 return string.Format("{0} {1} {2}", 26 bid, bname, color); 27 } 28 } 29 30 public class Reserves 31 { 32 public int sid { get; set; } 33 public int bid { get; set; } 34 public string rdate { get; set; } 35 // Overrides the Object.ToString() to provide a 36 // string representation of the object properties. 37 public override string ToString() 38 { 39 return string.Format("{0} {1} {2}", 40 sid, bid, rdate); 41 } 42 }
表的属性由对应类的数据表示,并用ToString函数输出一条记录数据。
下面进行数据初始化,以Sailors表为例:
1 private static List<Sailors> createSailors() 2 { 3 //将数据储存在list中 4 List<Sailors> sailors = new List<Sailors> { 5 new Sailors{ sid = 22,sname = "dustin",rating = 7, age= 45}, 6 new Sailors{sid = 29,sname = "brustus",rating = 1, age = 33}, 7 new Sailors{ sid = 31 ,sname = "lubber",rating = 8,age = 56 }, 8 new Sailors { sid = 32, sname = "andy", rating = 8,age = 26}, 9 new Sailors { sid = 58, sname = "rusty", rating = 10,age = 35}, 10 new Sailors { sid = 64 , sname = "horatio", rating = 7,age = 35}, 11 new Sailors { sid = 71,sname = "zorba", rating = 10, age = 35}, 12 new Sailors { sid = 74, sname = "horatio", rating = 9,age = 35}, 13 new Sailors { sid = 85, sname = "art", rating = 3,age = 26 }, 14 new Sailors { sid = 86,sname = "john", rating = 1,age = 17}, 15 new Sailors { sid = 95,sname = "bob", rating = 3,age= 64}, 16 new Sailors { sid = 96,sname = "frodo", rating = 3 , age = 26}, 17 new Sailors { sid = 98,sname = "tom",rating = 3,age = 17}, 18 }; 19 return sailors; 20 }
下面开始本次学习记录的重头戏,查询语法。
首先来个简单的示例,查询名字为lubber的水手的编号,代码如下:
1 public class Tester 2 { 3 static void Main() // Main program 4 { 5 //初始化数据 6 List<Reserves> reserves = new List<Reserves>(createReserves()); 7 List<Sailors> sailors = new List<Sailors>(createSailors()); 8 List<Boats> boats = new List<Boats>(createBoats()); 9 //查询语句 10 IEnumerable<Sailors> result = from sailor in sailors //指定范围变量和数据源 11 where sailor.sname == "lubber" //筛选条件 12 select sailor; //指明需要提取的数据,即映射 13 foreach (Sailors a in result) 14 { 15 Console.WriteLine(a.ToString()); 16 } 17 18 19 Console.ReadKey(); 20 } 21 ...... 22 }
输出如下:
是不是很简单?
上面代码7行的IEnumerable<Sailors>和13行的Sailors也可改成var匿名类型,即
1 var result = from sailor in sailors 2 where sailor.sname == "lubber" 3 select sailor; 4 foreach (var a in result) 5 { 6 Console.WriteLine(a.ToString()); 7 }
输出不变,由此可见匿名类型给我们带来的极大便利。
下面介绍联系各个表的join关键字,其基本形式是:[data source 1] join [data source 2] on [join condition],如查找定了103号船的水手的信息 就需要查询Sailors和Reserves两张表,代码如下:
1 ..... 2 var result = from sailor in sailors 3 join reserve in reserves on sailor.sid equals reserve.sid //join后跟数据源与条件 4 where reserve.bid == 103 5 select sailor; 6 foreach (var a in result) 7 { 8 Console.WriteLine(a.ToString()); 9 } 10 .....
输出如下:
加入更多的表依然是按上面添加join语句即可。
下面是结果的排序,使用orderby关键字,示例如下:
1 ...... 2 var result = from sailor in sailors 3 join reserve in reserves on sailor.sid equals reserve.sid 4 where reserve.bid == 103 5 orderby sailor.age//按水手年龄排序 6 select sailor; 7 foreach (var a in result) 8 { 9 Console.WriteLine(a.ToString()); 10 } 11 .......
输出结果如下:
我们可以注意到结果按年龄(最后一项记录)升序排列,即LINQ默认的排序是升序的,要改成讲叙的只需在orderby语句行的最后加上descending关键字即可,如 orderby sailor.age descending 即可实现目的。
下面谈一下分组查询,使用关键字group,by。如查询相同等级(rating)的水手姓名,代码如下:
1 ..... 2 var result = from sailor in sailors 3 orderby sailor.rating 4 group sailor by sailor.rating; 5 6 foreach (var gp in result) 7 { 8 Console.WriteLine("{0}", gp.Key); //gp.Key是分组查询的关键字,即sailor.rating 9 foreach (var a in gp) 10 Console.WriteLine("\t{0}", a); 11 } 12 .....
输出如下:
最后说一下LINQ中的Lambda表达式。比如上面第一个查询操作就可以用Lambda表达式写成下列形势:
1 ...... 2 var result = sailors.Where(sailor => sailor.sname == "lubber") 3 .Select(sailor => sailor); 4 5 foreach (var a in result) 6 { 7 Console.WriteLine(a.ToString()); 8 } 9 ......
本次学习记录到此为止,有机会我会添加新领悟的东西进去。
望各位老师大牛不吝赐教!