LINQ(集成化查询)

      LINQ可以对数组、集合等数据结构进行查询、筛选、排序等操作;也可以用于与数据库交互;也支持对XML的操作,使用LINQ技术可以动态创建、筛选和修改XML数据和直接操作XML文件。

一). LINQ基本语法:

      (1)所有的LINQ查询表达式都是以from....in....开头;

      (2)以select或group子句结束。以select子句结束表示从数据源序列筛选出元素;以group子句结束表示将从数据源序列中筛选出来的元素进行分组,并把每个分组放进查询结果集中。

例如:var result=from str in list select str;

         var result from str in list group s by str[0];   

).延迟执行与强制立即执行

   先看以下代码:var result=from str in list select str;当执行上述代码时,LINQ查询实际上并未执行,而是仅仅把用于查询的“命令”存放在result变量中,只到执行到遍历访问代码时才会执行查询:foreach(var a in result){。。。。。},这就是延迟执行。当然,可以调用Count,ToList,ToArray等方法来时查询立即执行,即使LINQ查询强行立即执行。

三).筛选、排序、分组

(1)在查询语句中,用where子句来设定筛选条件(一个或多个条件),如果where子句后面条件为真,则符合条件;若为假,则不符合条件。

例如:var a=from b in c where b>10 select b;

(2)对查询结果重新排序可以用orderby子句,默认情况下按升序排序,如果要进行降序排序,就必须在orderby子句后加上descending关键字。

例如:var a=from b in c orderby b select b;

(3)对数据进行分组要有分组依据,因此group一般与by关键字连用,格式如下:group <要进行分组的元素>by<分组依据>

如果要对分组的数据进行操作,可以在查询语句中储存个分组的数据,即在分组语句后面接上into关键字。如:group emp by emp.Department into eg;数据分组后会将每个分量都存入eg变量中,随后可以用select子句把存放在eg中的分组选择进行结果中。如下:group emp by emp.Department into eg select eg;这时候查询结果中的每个元素都是IGrouping<TKey,TElement>类型的对象,IGrouping<TKey,TElement>带了2个类型参数,TKey表示分组依据(Key)的类型,TElement表示每个分组中元素的类型,由于IGrouping接口继承自IEnumerable<out T>接口,因此,只要使用foreach循环就可以访问分组中的元素。

            // 示例数据源
            string[] arr = { "table", "use", "up", "take", "turn", "reset", "remove", "we", "wave", "work", "word" };

            // 查询数据源中的所有元素
            // 并以首字母作为分组依据
            var res = from s in arr
                      group s by s.ToUpper()[0];
            // 输出查询结果
            Console.WriteLine("共有{0}个分组。", res.Count());
            foreach (IGrouping<char, string> item in res)
            {
                Console.WriteLine("--------- {0} --------", item.Key);
                // 取出该分组中的元素
                foreach (string str in item)
                {
                    Console.WriteLine("  {0}", str);
                }
                Console.WriteLine();
            }

下面在看一例:

public class Student
    {
        /// <summary>
        /// 学员ID
        /// </summary>
        public uint StuID { get; set; }
        /// <summary>
        /// 学员姓名
        /// </summary>
        public string StuName { get; set; }
        /// <summary>
        /// 课程
        /// </summary>
        public string Course { get; set; }
    }
            Student[] students =
            {
                new Student { StuID = 1, StuName = "小陈", Course = "C++基础" },
                new Student { StuID = 2, StuName = "小林", Course = "VB入门" },
                new Student { StuID = 3, StuName = "小邓", Course = "C++基础" },
                new Student { StuID = 4, StuName = "小李", Course = "C#客户端开发" },
                new Student { StuID = 5, StuName = "小唐", Course = "C++基础" },
                new Student { StuID = 6, StuName = "小周", Course = "VB入门" },
                new Student { StuID = 7, StuName = "小张", Course = "VB入门" },
                new Student { StuID = 8, StuName = "小吴", Course = "C#客户端开发" },
                new Student { StuID = 9, StuName = "小孙", Course = "C++基础" },
                new Student { StuID = 10, StuName = "小孟", Course = "C#客户端开发" }
            };
            // 筛选出学号大于5的学员
            // 并按课程进行分组
            // 学号按降序排列
            var res = from s in students
                  orderby s.StuID descending
                  where s.StuID > 5
                  group s by s.Course into g
                  select g;
            foreach (var g in res)
            {
                Console.WriteLine("----- {0} -----", g.Key);
                foreach (Student stu in g)
                {
                    Console.WriteLine("学号:{0},姓名:{1},课程:{2}", stu.StuID, stu.StuName, stu.Course);
                }
                Console.WriteLine();
            }

四).复杂查询

(1)动态创建类型

在比较复杂的查询中,查询结果通常会生成一个新的类型,以使其内部包含来自多个数据序列的属性。许多时候,这些新类型并不是固定的,不同的查询需求会产生不同的结果,如果为每种查询结果都去定义相应的类,那有可能变得很复杂,面对这种情况,使用动态类型是较理想的选择。动态类型无需事先去定义类,即可根据代码上下文的需要动态地去创建新类型,实现方法是运用new运算符,创建的新类型并没有确切的名称,是由编译器自动分配的,因此在声明量时应使用var关键字,由编译器自动去识别其类型。

例如:

            var a = new
            {
                b = "cajj",
                c = 123
            };
            Console.WriteLine("{0}    {1}", a.b, a.c);

也可以使用dynamic关键字来声明用于引用匿名类型的变量。使用dynamic声明的变量属于动态类型,在编译阶段不进行解析,只在运行时动态解析。

例如:

dynamic b = new
            {
                Name = "Java",
                Age = 18,
                Birth = new DateTime(1997, 07, 06)
            };
            Console.WriteLine("Name={0}   Age={1}   Birth={2:yyyy-M-d}", b.Name, b.Age, b.Birth);

(2)联合查询

联合查询主要通过jion关键字来完成的。所谓的联合查询,可以理解为联合多个数据序列进行查询,并从中返回查询结果。查询结果中的数据可能来自于多个数据序列。多个数据序列要进行联合,需要提供一个联合条件才能使多个序列完成正确的联合,所以,jion关键字后面紧跟着on关键字,并通过equals关键字来判断联合条件是否成立。

代码如下:

    /// <summary>
    /// 图书分类信息
    /// </summary>
    public class Category
    {
        /// <summary>
        /// 分别ID
        /// </summary>
        public int catID { get; set; }
        /// <summary>
        /// 分类名
        /// </summary>
        public string catName { get; set; }
    }

    /// <summary>
    /// 图书信息
    /// </summary>
    public class BookInfo
    {
        /// <summary>
        /// 图书ID
        /// </summary>
        public int BookID { get; set; }
        /// <summary>
        /// 书名
        /// </summary>
        public string BookName { get; set; }
        /// <summary>
        /// 图书所属分类的ID
        /// </summary>
        public int CateID { get; set; }
    }
            // 图书分类示例数据
            List<Category> bookCategs = new List<Category>
            {
                new Category { catID = 201, catName = "文学类" },
                new Category { catID = 202, catName = "经济管理类" },
                new Category { catID = 203, catName = "机械工程类" },
                new Category { catID = 204, catName = "法律基础类" }
            };

            // 图书信息示例数据
            List<BookInfo> books = new List<BookInfo>
            {
                new BookInfo { BookID = 1, BookName = "图书01", CateID = 202 },
                new BookInfo { BookID = 2, BookName = "图书02",CateID = 204 },
                new BookInfo { BookID = 3, BookName = "图书03", CateID = 201 },
                new BookInfo { BookID = 4, BookName = "图书04", CateID = 202 },
                new BookInfo { BookID = 5, BookName = "图书05",CateID = 204 },
                new BookInfo { BookID = 6, BookName = "图书06", CateID = 204 },
                new BookInfo { BookID = 7, BookName = "图书07", CateID = 203 },
                new BookInfo { BookID = 8, BookName = "图书08",CateID = 202 },
                new BookInfo { BookID = 9, BookName = "图书09", CateID = 203 },
                new BookInfo { BookID = 10, BookName = "图书10", CateID = 202 },
                new BookInfo { BookID = 11, BookName = "图书11", CateID = 201 },
                new BookInfo { BookID = 12, BookName = "图书12", CateID = 203 },
                new BookInfo { BookID = 13, BookName = "图书13", CateID = 201 },
                new BookInfo { BookID = 14, BookName = "图书14", CateID = 204 },
                new BookInfo { BookID = 15, BookName = "图书15", CateID = 203 },
                new BookInfo { BookID = 16, BookName = "图书16", CateID = 202 },
            };

接下来,联合books和bookCategs两个数据序列,代码如下:

            // 联合查询,并产生新的类型
            var qryres = from b in books
                         join c in bookCategs on b.CateID equals c.catID
                         select new
                         {
                             b.BookName,
                             c.catName
                         };
            // 输出结果
            foreach (var bitem in qryres)
            {
                Console.WriteLine("图书名:{0},所属分类:{1}", bitem.BookName, bitem.catName);
            }

上述代码,select子句使用new运算符动态创建匿名类型,并使用BookInfo对象的BookName属性和Category对象的catName属性作为新类型的属性,也就是说,创建的匿名类型具有BookName和catName两个属性,当然,也可以为动态创建的匿名类型使用自己命名的属性名,代码如下:

            var qryres2 =
                from bk in books
                join bc in bookCategs on bk.CateID equals bc.catID
                select new
                    {
                        Book_ID = bk.BookID,
                        Book_Name = bk.BookName,
                        Book_Cate = bc.catName
                    };
            // 输出结果
            foreach (var bk in qryres2)
            {
                Console.WriteLine("图书ID:{0},图书名:{1},所属分类:{2}", bk.Book_ID, bk.Book_Name, bk.Book_Cate);
            }

在上面的例子中,与每个BookInfo对象实例的CateID属性相对应的Category对象都能在bookCategs列表中找到,这种的联合查询称为”内部联合“。下面,就考虑另一种情况,即当序列A与序列B进行联合查询时,在序列B中找不到与序列A的项匹配的元素。

代码如下:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 
  7 namespace My
  8 {
  9 
 10     #region 定义类型
 11     /// <summary>
 12     /// 专辑信息
 13     /// </summary>
 14     public class Album
 15     {
 16         /// <summary>
 17         /// 专辑名称
 18         /// </summary>
 19         public string Title { get; set; }
 20         /// <summary>
 21         /// 发行年份
 22         /// </summary>
 23         public int Year { get; set; }
 24         /// <summary>
 25         /// 专辑描述
 26         /// </summary>
 27         public string Description { get; set; }
 28     }
 29 
 30     /// <summary>
 31     /// 曲目信息
 32     /// </summary>
 33     public class Track
 34     {
 35         /// <summary>
 36         /// 曲目名称
 37         /// </summary>
 38         public string Name { get; set; }
 39         /// <summary>
 40         /// 艺术家名字
 41         /// </summary>
 42         public string Artist { get; set; }
 43         /// <summary>
 44         /// 所属专辑
 45         /// </summary>
 46         public Album AlbumOf { get; set; }
 47     }
 48     #endregion
 49 
 50     class Program
 51     {
 52         static void Main(string[] args)
 53         {
 54             // 专辑列表
 55             Album album1 = new Album { Title = "专辑 1", Year = 2003, Description = "这是第一张专辑。" };
 56             Album album2 = new Album { Title = "专辑 2", Year = 2009, Description = "这是第二张专辑。" };
 57             List<Album> albums = new List<Album> { album1, album2 };
 58 
 59             // 曲目列表
 60             Track track1 = new Track { Name = "曲目 1", Artist = "艺术家 1", AlbumOf = album1 };
 61             Track track2 = new Track { Name = "曲目 2", Artist = "艺术家 2", AlbumOf = album2 };
 62             Track track3 = new Track { Name = "曲目 3", Artist = "艺术家 3", AlbumOf = album2 };
 63             Track track4 = new Track { Name = "曲目 4", Artist = "艺术家 4", AlbumOf = album1 };
 64             Track track5 = new Track { Name = "曲目 5", Artist = "艺术家 5", AlbumOf = album2 };
 65             Track track6 = new Track { Name = "曲目 6", Artist = "艺术家 6", AlbumOf = null };
 66             List<Track> tracks = new List<Track> { track1, track2, track3, track4, track5, track6 };
 67 
 68             // 开始查询
 69             var res1 = from t in tracks
 70                        join a in albums on t.AlbumOf equals a into g1
 71                        from a1 in g1.DefaultIfEmpty()
 72                        select new
 73                        {
 74                            TrackName = t.Name,
 75                            Artist = t.Artist,
 76                            AlbumName = a1 == null ? "未知专辑" : a1.Title
 77                        };
 78 
 79             // 以下代码会发生异常
 80             //var res1 = from t in tracks
 81             //           join a in albums on t.AlbumOf equals a into g1
 82             //           from a1 in g1.DefaultIfEmpty()
 83             //           select new
 84             //           {
 85             //               TrackName = t.Name,
 86             //               Artist = t.Artist,
 87             //               AlbumName = a1.Title
 88             //           };
 89 
 90             // 输出结果
 91             foreach (var item in res1)
 92             {
 93                 Console.WriteLine("曲目:{0},艺术家:{1},专辑:{2}", item.TrackName, item.Artist, item.AlbumName);
 94             }
 95 
 96             Console.WriteLine();
 97 
 98             var res2 = from t in tracks
 99                        join a in albums on t.AlbumOf equals a into g
100                        from a2 in g.DefaultIfEmpty(new Album { Title = "<未知>", Year = 0, Description = "<无>" })
101                        select new
102                            {
103                                TrackName = t.Name,
104                                Year = a2.Year,
105                                Artist = t.Artist,
106                                AlbumName = a2.Title,
107                                AlbumDesc = a2.Description
108                            };
109             // 输出结果
110             foreach (var item in res2)
111             {
112                 Console.WriteLine("曲目:{0},年份:{1},艺术家:{2},专辑:{3},专辑描述:{4}", item.TrackName, item.Year, item.Artist, item.AlbumName, item.AlbumDesc);
113             }
114 
115             Console.Read();
116         }
117     }
118 }

(3) 嵌套查询

嵌套查询是指在一个查询内部嵌套这另一个查询,其实嵌套查询是比较简单的,就直接看个例子吧。

代码如下:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 
  7 namespace My
  8 {
  9     #region 定义类型
 10     /// <summary>
 11     /// 商品信息
 12     /// </summary>
 13     public class Goods
 14     {
 15         /// <summary>
 16         /// 商品编号
 17         /// </summary>
 18         public string GsNo { get; set; }
 19         /// <summary>
 20         /// 商品名称
 21         /// </summary>
 22         public string GsName { get; set; }
 23         /// <summary>
 24         /// 商品单价
 25         /// </summary>
 26         public double GsPrice { get; set; }
 27     }
 28 
 29     /// <summary>
 30     /// 销售单信息
 31     /// </summary>
 32     public class SalesOrder
 33     {
 34         /// <summary>
 35         /// 单据ID
 36         /// </summary>
 37         public int OrderID { get; set; }
 38         /// <summary>
 39         /// 商品编号
 40         /// </summary>
 41         public string GoodsNo { get; set; }
 42         /// <summary>
 43         /// 销售时间
 44         /// </summary>
 45         public DateTime Time { get; set; }
 46         /// <summary>
 47         /// 销售数量
 48         /// </summary>
 49         public int Qty { get; set; }
 50     }
 51     #endregion
 52 
 53     class Program
 54     {
 55         static void Main(string[] args)
 56         {
 57             // 商品信息 - 示例数据
 58             Goods[] goodsArr = 
 59             {
 60                 new Goods { GsNo = "G-1", GsName = "报纸", GsPrice = 1.50d },
 61                 new Goods { GsNo = "G-2", GsName = "食盐", GsPrice = 3.65d },
 62                 new Goods { GsNo = "G-3", GsName = "火柴", GsPrice = 0.50d },
 63                 new Goods { GsNo = "G-4", GsName = "灯泡", GsPrice = 12.30d },
 64                 new Goods { GsNo = "G-5", GsName = "剪刀", GsPrice = 4.50d }
 65             };
 66 
 67             // 销售单据 - 示例数据
 68             SalesOrder[] orders =
 69             {
 70                 new SalesOrder { OrderID = 1, GoodsNo = goodsArr[0].GsNo, Qty = 3, Time = new DateTime(2014, 1, 2) },
 71                 new SalesOrder { OrderID = 2, GoodsNo = goodsArr[1].GsNo, Qty = 5, Time = new DateTime(2014, 1, 4) },
 72                 new SalesOrder { OrderID = 3, GoodsNo = goodsArr[2].GsNo, Qty = 2, Time = new DateTime(2014, 1, 12) },
 73                 new SalesOrder { OrderID = 4, GoodsNo = goodsArr[3].GsNo, Qty = 6, Time = new DateTime(2014, 1, 20) },
 74                 new SalesOrder { OrderID = 5, GoodsNo = goodsArr[4].GsNo, Qty = 1, Time = new DateTime(2014, 2, 3) },
 75                 new SalesOrder { OrderID = 6, GoodsNo = goodsArr[2].GsNo, Qty = 4, Time = new DateTime(2014, 2, 9) },
 76                 new SalesOrder { OrderID = 7, GoodsNo = goodsArr[1].GsNo, Qty = 8, Time = new DateTime(2014, 3, 13) },
 77                 new SalesOrder { OrderID = 8, GoodsNo = goodsArr[3].GsNo, Qty = 10, Time = new DateTime(2014, 3, 11) },
 78                 new SalesOrder { OrderID = 9, GoodsNo = goodsArr[0].GsNo, Qty = 15, Time = new DateTime(2014, 3, 18) },
 79                 new SalesOrder { OrderID = 10, GoodsNo = goodsArr[0].GsNo, Qty = 7, Time = new DateTime(2014, 2, 22) },
 80                 new SalesOrder { OrderID = 11, GoodsNo = goodsArr[3].GsNo, Qty = 20, Time = new DateTime(2014, 3, 17) },
 81                 new SalesOrder { OrderID = 12, GoodsNo = goodsArr[1].GsNo, Qty = 13, Time = new DateTime(2014, 1, 29) },
 82                 new SalesOrder { OrderID = 13, GoodsNo = goodsArr[2].GsNo, Qty = 8, Time = new DateTime(2014, 2, 9) },
 83                 new SalesOrder { OrderID = 14, GoodsNo = goodsArr[4].GsNo, Qty = 21, Time = new DateTime(2014, 3, 16) },
 84                 new SalesOrder { OrderID = 15, GoodsNo = goodsArr[2].GsNo, Qty = 6, Time = new DateTime(2014, 2, 15) }
 85             };
 86 
 87             /*
 88              * 查询并计算出各个商品的
 89              * 总销售额
 90              */
 91             var res = from g in goodsArr
 92                       let totalQty =
 93                       /* 以下为嵌套查询 */
 94                       (from od in orders
 95                        where od.GoodsNo == g.GsNo
 96                        select od).Sum(odr => odr.Qty)
 97                       select new
 98                           {
 99                               g.GsNo,
100                               g.GsName,
101                               /* 计算总销售额 */
102                               Total = totalQty * g.GsPrice
103                           };
104 
105             // 输出查询结果
106             foreach (var item in res)
107             {
108                 Console.WriteLine("编号:{0},商品:{1},总额:{2:N2}", item.GsNo, item.GsName, item.Total);
109             }
110 
111             Console.Read();
112         }
113     }
114 }

博客写到这,可以看到其实LINQ查询是比较简单的,只要仔细,就不会出错的。。。。

 

posted @ 2015-10-30 13:18  追求沉默者  阅读(669)  评论(0编辑  收藏  举报