LINQ驱动数据的查询功能

一、LINQ概念

LINQ是微软在.NetFramework3.5中新加入的语言功能,在语言中以程序代码方式处理集合的能力。

1.1 LINQ VS 循环处理

在我刚工作时候,对于集合对象的处理一般是采用循环这个集合处理,在处理实值类型上这样做效率还行,但是如果集合内是引用类型,使用LINQ就方便的多,例如一个程序要计算课程的总分和平均分,实体分别是Student和StudentScore

类的申明如下:

 /// <summary>
    /// 学生实体
    /// </summary>
   public class Student
    {
       /// <summary>
       /// 学生主键
       /// </summary>
       public string StudentID { get; set; }

       /// <summary>
       /// 学生名称
       /// </summary>
       public string StudentName { get; set;}

    }
    /// <summary>
    /// 学生分数实体
    /// </summary>
   public class StudentScore
    {
       /// <summary>
       /// 学生分数主键
       /// </summary>
       public string ScoreId { get; set; }

       /// <summary>
       ///学生分数
       /// </summary>
       public int Score { get; set; }
    }

使用循环方式实现统计本班总分和平均分代码如下:

            List<Student> students = GetStudents();
            List<StudentScore> CSScoreList = GetCSScores();
            List<StudentScore> DBScoreList = GetDBScores();

            double CSSum = 0.0, DBSum = 0.0;
            //循环C#集合
            foreach (StudentScore csScore in CSScoreList)
            {
                CSSum = CSSum + csScore.Score;
            }
            //循环DB集合
            foreach (StudentScore dbScore in DBScoreList)
            {
                DBSum += dbScore.Score;
            }
            Console.WriteLine("本班的C#总分是:{0},平均分是:{1}", CSSum, CSSum/students.Count);
            Console.WriteLine("本班的SQL总分是:{0},平均分是:{1}", DBSum, DBSum / students.Count);
            Console.ReadKey();

使用Linq的代码处理如下

 Console.WriteLine("本班的C#总分是:{0},平均分是:{1}", CSScoreList.Sum(t=>t.Score),CSScoreList.Average(t=>t.Score));
            Console.WriteLine("本班的SQL总分是:{0},平均分是:{1}", DBScoreList.Sum(t => t.Score), DBScoreList.Average(t => t.Score));

使用LINQ中最简单的例子,说明LINQ给我们带来的便利。

二、LINQ的基础

LINQ本身以IEnumerable<T>两个接口为基础,IEnumerable<T>则负责泛型的集合,目前.NET Framework内的泛型集合类 System.Collection.Generic 命名空间都已实现 IEnumerable<T>,一般来说在.NET内的所有集合对象都能使用LINQ进行处理,如果不引用System.Linq命名空间,所有Linq功能都无法使用。

2.1 扩展方法

扩展方法赋予了程序设计语言可在现有类下扩展类的功能,且不需要修改原本程序代码。实现扩展方法十分简单,只需要建立一个静态类,名称建议用 "要扩展的类名称"+Extension字样,例如扩展Int的方法,就将类名命名为Int32Extension,接下来在类内加入要扩展的方法,但是要注意两件事:

1.必须是静态方法,且名称不能和现有的方法冲突

2.参数至少有一个,且类型为扩展类型,格式是"this[要扩展的类名称][参数名称]",若有两个以上的参数,则扩展类型放在第一个不能设置默认值。

 /// <summary>
    /// 定义INT32扩展类
    /// </summary>
    public static class Int32Extension
    {
        public static string FormartForMoney(this Int32 value)
        {
            return value.ToString("$###,###,###,##0");
        }
    }

    /// <summary>
    /// 定义Double类型的拓展类
    /// </summary>
    public static class DoubleExtension
    {
        public static string FormartPercent(this double value)
        {
            return value.ToString("0.00%");
        }
    }
 int money = 12345;
            double d = 0.12345;
            Console.WriteLine("{0}", money.FormartForMoney());
            Console.WriteLine("{0}", d.FormartPercent());
            Console.ReadKey();

2.2 匿名类型与对象初始化器

语法中有一个select new ,可以按所设置的属性自动产生类对象,并且自动赋予数值,这个语法包含了两个语言功能:对象初始化器与匿名类型。

对象初始化器:允许程序中通过声明方式直接给对象属性进行数值的初始化,而不必建立有参数的构造函数。(字典类型必须按照特定格式初始化)

匿名类型:不定义类的情况下生成新的类,Linq中常用。其中有几点限制:

(1)  匿名类型只在同一个函数内,如果要在其他函数共享必须动用Reflection或者是利用.NET4.0提供的动态类型机制。

(2)  匿名类型只能有属性,不可以有方法、事件、或字段等。

(3)  两个匿名类型对象的相等,必须要两个对象的属性值都相等才行。

(4) 匿名类型的初始化只能利用对象初始化器来进行,其属性生成后会变成只读。

2.3 类型推论

使用匿名类型在Linq中变量类型无法确定,如果试用IEnumerable<object>就失去强类型的好处,在.NET3.5中只要使用Linq并且以select new来产生结果的查询,其变量类型声明会使用var类型表示,var类型代表编译器腿短这个变量的类型,在LINQ中复杂查询如果是嵌套的错误率较高,所以用var替代。var的限制如下:

(1)使用var类型赋值语句时右边不能为null,否则编译器无法推断其类型。

(2)var类型只能用于局部变量的声明,不能用于全局变量,类层变量或者是函数的返回值。

(3)var类型不可用在匿名委派或者是方法群组中。

2.4 yield指令与延迟查询

微软提供了一个指令yield,它可以只传回每个元素的方式自动生成IEnumerable<T>对象

 private static IEnumerable<int> GetYieldResult(IEnumerable<int> param)
        {
            foreach (var num in param)
            {
                if (num > 5)
                {
                    yield break;
                }
                else
                {
                    yield return num;
                }
            }
        }

yield指令乍看之下只是精简写法,实际上这个方法的执行推迟到真正查询才触发,例如调用这个方法时候并不会执行,当执行ToList()时候才执行,这个机制称为延迟查询或者延迟执行。

三、Linq语句

Linq语句主要应用于集合的处理上, 这就是Linq的价值所在,而对于外部数据源,只要有相应的LINQ provider就一样享有Linq的完整功能。

通过例子学习LINQ是我的做法,例如以下就是求两个集合中相同存在的数字:

            List<int> list1 = new List<int>() { 1, 3, 5, 7, 9, 10, 15 };
            List<int> list2 = new List<int>() { 2, 4, 6, 8, 10, 15 };
            var query = from item1 in list1 join item2 in list2 on item1 equals item2 select item1;
            foreach (var q in query)
            {
                Console.WriteLine("{0}", q);
            }

或者是查询目前某个订单的销售总数

var query=from o in orderList

        group by o.ProductID into g

         select new{ProductID=g.Key,Qty=g.sum(t=>t.ProductID)}

四、Linq函数

Where():查询结果过滤

  Select():选取数据

SelectMany():相当于数据库的Cross Join,这个的查询结果是笛卡尔积,就是两个表数据的乘积,将表一所有数据和表二连接,通过例子:

IEnumerable<int> selectMany = list1.SelectMany(t=>list2).ToList(); 也可以写成   IEnumerable<int> selectMany = list1.SelectMany((int o) => { return list2; }).ToList();  selectMany()参数是Func<int,IEnumerable<TResult>>

GroupBy():本身具有延迟查询的特性:

             List<int> groupList = new List<int>() { 1, 2, 3, 3, 2, 1, 6, 8, 34, 100, 3, 2, 5 };
            IEnumerable<IGrouping<int,int>> groupquery = groupList.GroupBy(t => t);
            foreach (var group in groupquery)
            {
                Console.WriteLine("{0}的数量有{1}个", group.Key, group.Count());
            }

ToLookup():和GroupBy()类似没有延迟加载,但是它会产生一个新的集合对象,这个集合对象由ILookup<TKey,TElement>所组成,允许多个键存在,一个键包含很多关联的实值例如:

 var nameGroup = new[]
            {
                new {name="CallmeYhz",age=27,group="A"},
                new {name="周公瑾",age=32,group="B"},
                new {name="孔明",age=68,group="A"},
                new {name="郭奉孝",age=22,group="C"},
                new {name="孙仲谋",age=55,group="B"},
                new {name="子龙",age=63,group="A"}
            };

            var ToLookUp = nameGroup.ToLookup(t => t.group);
            foreach (var bigGroup in ToLookUp)
            {
                Console.WriteLine("当前是组{0}", bigGroup.Key);
                foreach (var smallGroup in bigGroup)
                {
                    Console.Write("名字是:{0},年龄是:{1}", smallGroup.name, smallGroup.age);
                }
                Console.WriteLine();
                Console.WriteLine();
                Console.WriteLine();
            }

Join():

在linq语句中使用

  List<int> list1 = new List<int>() { 1, 3, 5, 9, 7, 10 };
            List<int> list2 = new List<int>() { 2, 4, 6, 7, 9, 11 };
            var query = from item1 in list1
                        join item2 in list2 on item1 equals  item2
                        select item1;

            query.ToList().ForEach(t => Console.Write("{0} ", t));

由此例子可知,它将原本的集合视为TOuter而将传入的集合视为TInner,而还要决定由哪个属性或者成员当Key。例子中list1为本身,注意顺序。

上面用linq函数实现则为:

  

List<int> list1 = new List<int>() { 1, 3, 5, 9, 7, 10 };
            List<int> list2 = new List<int>() { 2, 4, 6, 7, 9, 11 };
            var query = list1.Join(list2, a=>a, b=>b,(a,b)=>b);
            query.ToList().ForEach(t => Console.Write("{0} ", t));

总结:目前常用的联接模式,Inner join由Enumerable<T>.Join()实现,CROSS JOIN 由Enumerable<T>SelectMany实现,还有一种Join模式没有考虑:LEFT OUTER JOIN 模式,要实现这个模式必须借助GroupJoin()。

GroupJoin():

List<int> list1 = new List<int>() { 1, 3, 5, 9, 7, 10 };
            List<int> list2 = new List<int>() { 2, 4, 6, 7, 7, 9, 11 };
            var query = list1.GroupJoin(
                list2,
                a => a,
                b => b,
                (a, b) => new { v = a, c = b.Count() });

            query.ToList().ForEach(t => Console.WriteLine("找到list2中有{0}个{1}", t.c, t.v));

时间: 2024-10-14 12:02:51

LINQ驱动数据的查询功能的相关文章

linq 大数据 sql 查询及分页优化

前提: 需要nuget   PredicateLib   0.0.5: SqlServer  2008R2 (建议安装 64 位): .net 4.5 或以上: 当前电脑配置: I7 4核  3.6GHZ,8G 内存 (办公电脑 ,win10 64位) 描述: 在实际项目中我们会遇到多个表关联查询数据,并进行分页操作:当数据量很大的时候如(500万或以上)的时候,分页很吃力,特别还需要一些模糊查询,排序的时候会导致很慢: 本文章主要解决分页及多个数据表关系查询速度慢的问题: 解决办法及优化过程:

C#程序中使用LINQ to XML来查询XML格式数据的实例

LINQ to XML 是一种启用了 LINQ 的内存 XML 编程接口,使用它,可以在 .NET Framework 编程语言中处理 XML.它将 XML 文档置于内存中,这一点很像文档对象模型 (DOM). 您可以查询和修改 XML 文档,修改之后,可以将其另存为文件,也可以将其序列化然后通过网络发送. 但是,LINQ to XML 与 DOM 不同: 它提供一种新的对象模型,这是一种更轻量的模型,使用也更方便,这种模型利用了 VisualC# 2008 在语言方面的改进.LINQ to X

[.NET] SQL数据分页查询

[.NET] SQL数据分页查询 程序下载 范例下载:点此下载 原始码下载:点此下载 NuGet封装:点此下载 数据查询 开发系统时,使用C#执行SQL查询指令,就可以从SQL数据库里查询所需数据. SELECT Id, Name FROM Users 数据分页查询 当数据量过多时,系统会需要采用分页的方式来分批取得数据.这时可以改写原有的SQL查询指令,在其中加入ROW_NUMBER(),来为每笔资料打上编号.后续依照系统需求,取得某个编号范围内的数据,就完成在系统中提供数据分页查询的功能.(

linq根据传入数据集合查询对应子级数据

工作中经常用到的linq根据传入数据集合查询对应子级数据,整理共享,希望大家都能用得上,代码中doublesArray 为父节点对应ID数据集合,再根据ID数据集合查询全部子级数据. //获取缓存数据 object obj = Caching.GetCache(CacheKey + UModel.RoleId); if (obj != null)//判读缓存数据是否null { SysFunList = (DataSet)obj; } else { string strSql = "select

linq依据传入数据集合查询相应子级数据

工作中经经常使用到的linq依据传入数据集合查询相应子级数据,整理共享,希望大家都能用得上,代码中doublesArray 为父节点相应ID数据集合,再依据ID数据集合查询所有子级数据. //获取缓存数据 object obj = Caching.GetCache(CacheKey + UModel.RoleId); if (obj != null)//判读缓存数据是否null { SysFunList = (DataSet)obj; } else { string strSql = "sele

雷林鹏分享:jQuery EasyUI 数据网格 - 添加查询功能

jQuery EasyUI 数据网格 - 添加查询功能 本实例演示如何从数据库得到数据,并将它们显示在数据网格(datagrid)中.然后演示如何根据用户输入的搜索关键词搜寻显示结果. 创建数据网格(DataGrid) 创建带有分页功能的数据网格(datagrid),然后添加工具栏到其中. url="datagrid24_getdata.php" toolbar="#tb" title="Load Data" iconCls="icon

SQL server 数据查询功能 中

查询数据 排序 查询结果集通常是按照id排序的,也就是根据主键排序.这也是大部分数据库的做法.如果我们要根据其他条件排序怎么办?可以加上ORDER BY子句. 例如按照成绩从低到高进行排序: SELECT id, name, gender, score FROM students ORDER BY score; 如果要反过来,按照成绩从高到底排序,我们可以加上DESC表示"倒序": SELECT id, name, gender, score FROM students ORDER B

SQL server 数据查询功能 下

查询数据 多表查询 SELECT查询不但可以从一张表查询数据,还可以从多张表同时查询数据.查询多张表的语法是:SELECT * FROM <表1> <表2>. 例如,同时从students表和classes表的"乘积",即查询数据,可以这么写: SELECT * FROM students, classes; 这种一次查询两个表的数据,查询的结果也是一个二维表,它是students表和classes表的"乘积",即students表的每一行与

组合查询功能实现

前言 这是我的第二篇文章,这是我之前做的ERP项目的时候设计实现的.在这个ERP系统中,功能比较多,表设计的时候建立了很多业务表.对于一些业务表需要执行很多查询,客户要求针对不同的字段进行查询,基于我们之前的设计,针对不同的查询条件设计不同的DAL方法,通过不同的方法签名来实现客户的对于不同条件查询的要求.但是这种解决方案会让程序员很被动,久而久之整个DAL层会显得很臃肿. 面对这样的困境,考虑是否可以实现用一个通用的DAL方法来代替所有的不同筛选条件查询方法,因为这些查询方法内部的逻辑是一样的