一、什么是Linq

Linq是语言集成查询(Language Integrated Query)的简称,是visual Studio 2008和.NET Framework 3.5版本中一项突破性的创新,它在对象领域和数据领域之间架起了一座桥梁。

Linq支持各种数据源:

1、ADO.NET DataSet

2、XML文档

3、SQL Server数据库

4、支持IEnumerable或泛型IEnumerable(T)接口的任意对象集合

5、更多。。。

二、Linq的优点

  • 传统的SQL查询
select FirstName,LastName,* from Customers
where city = 'Shanghai'
order by district

简单的字符串表示,没有编译时类型检查,没有IDE的智能感知支持。

以上例子只是针对SQL,针对不同的数据源,例如XML文档、各种WEB服务等我们还要学习不同的查询方法。

  • Linq查询示例

完全类型检查和IDE智能感知支持。

三、Linq查询的步骤

所有的Linq查询操作都由以下三个不同的操作组成:

  • 获得数据源
  • 创建查询
  • 执行查询

数据源

  • 想要使用Linq进行查询,数据源必须支持IEnumerable或IEnumerable(T)泛型接口或派生接口(如泛型的IQueryable(T)接口)。

查询

  • 查询指定要从数据源中检索的信息
  • 查询还可以指定在返回这些信息之前如何对其进行排序、分组和结构化
  • 查询存储在查询变量中,并用查询表达式进行初始化。为使编写查询的工作更加容易,C#引入了新的查询语法

查询执行

  • 查询变量本身只是存储查询命令。实际的查询执行会延迟在foreach语句中循环访问变量时发生。此概念称为“延迟执行”。
  • 强制立即执行,可以通过以下两个方法,使得Linq立即执行查询

      执行聚合函数(Count、Max、Average、First)。

      调用ToList(<T>Source)或ToArray(<T>Source)方法缓存结果。

四、查询基本操作

from子句

用于获取数据源

var queryAllCustomers=
from cust in Customers
select cust;
  • 查询表达式必须以from子句开头
  • 例子中cust是范围变量,范围变量类似于foreach循环中的迭代变量,但在查询表达式中,实际上不发生迭代。执行查询时,范围变量将用作对Customers中的每个后续元素的引用。因为编译器可以推断cust的类型,所以不必显示指定此类型。
  • Customers是数据源,实现了IEnumerable或IEnumerable(T)或其派生接口的。

复合from子句

在某些情况下,原序列中的每个元素本身可能是序列,也可能包含序列。用于访问某个数据源中的内部集合。

需求:查询出成绩有90分以上的学生,得到他们的名字和成绩

//数据源
IList<Student> students = new List<Student>
{
new Student{ Name="Kevin", Score=new List<int>{,,,}},
new Student{ Name="Jackie",Score=new List<int>{,,,}},
new Student{ Name="Helen",Score=new List<int>{,,,}}
}; //使用复合from子句查询命令
var getStudent =
from student in students
from score in student.Score
where score >
select new { Name=student.Name,Score=score};

分析:从代码中,我们可以看到学生对象中有个Score属性,Score属性本身就是List集合,这时候我们就要用到复合from子句进行查询了。首先遍历学生对象集合中的每个学生对象,然后在用另一个from子句,对每个学生对象中的Score属性进行遍历,筛选出含有90分以上的学生信息进行返回。

使用let子句扩展范围变量

用于创建查询自身的范围变量

需求:将字符串数组中的两句英文语句中所有的元音字母打头的单词输出到控制台

string[] strings ={
"I am a new Student.",
"You are a talent"
}; var query = from sentences in strings
let words = sentences.Split(' ')
from word in words
let w = word.ToLower()
where w[] == 'a' || w[] == 'e' || w[] == 'i' || w[] == 'o' ||
w[] == 'u'
select word; foreach (var word in query)
{
Console.Write(word + ",");
}

分析:首先遍历字符串数组中的每个字符串,用let子句创建查询自身的范围变量words,并调用Split(' ')方法,将每个字符串中以空格分割为单词存入words变量中,然后再次使用let子句创建查询自身的范围变量word,并调用ToLower()方法,将每个单词都变为小写,最后筛选出首字母为元音的单词进行返回。

说明:let语句是重命名。let位于第一个from和select语句之间。

这个例子从联接投影出最终“Let”表达式:

var q =
from c in db.Customers
join o in db.Orders on c.CustomerID
equals o.CustomerID into ords
let z = c.City + c.Country
from o in ords
select new
{
c.ContactName,
o.OrderID,
z
};

where子句

将一个布尔条件("谓词")应用于每个源元素(由范围变量引用),并返回满足指定条件的元素。

适用场景:实现过滤,查询等功能。

说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句。

Where操作包括3种形式,分别为简单形式、关系条件形式、First()形式。下面分别用实例举例下:

1)简单形式:

例如:使用where筛选在伦敦的客户

var q =
from c in db.Customers
where c.City == "London"
select c;

再如:筛选1994 年或之后雇用的雇员:

var q =
from e in db.Employees
where e.HireDate >= new DateTime(, , )
select e;

2)关系条件形式:

筛选库存量在订货点水平之下但未断货的产品:

var q =
from p in db.Products
where p.UnitsInStock <= p.ReorderLevel && !p.Discontinued
select p;

筛选出UnitPrice 大于10 或已停产的产品:

var q =
from p in db.Products
where p.UnitPrice > 10m || p.Discontinued
select p;

下面这个例子是调用两次where以筛选出UnitPrice大于10且已停产的产品。

var q =
db.Products.Where(p=>p.UnitPrice > 10m).Where(p=>p.Discontinued);

3)First()形式:

返回集合中的一个元素,其实质就是在SQL语句中加TOP (1)。

简单用法:选择表中的第一个发货方。

Shipper shipper = db.Shippers.First();

元素:选择CustomerID 为“BONAP”的单个客户

Customer cust = db.Customers.First(c => c.CustomerID == "BONAP");

条件:选择运费大于 10.00 的订单:

Order ord = db.Orders.First(o => o.Freight > 10.00M);

其他示例代码:

需求:将数组中小于5的偶数查询出来输出到控制台

//数据源
int[] arr = { , , , , , , , , , }; //使用Where子句查询的查询语句
var query = from a in arr
where a < && a % ==
select a; //执行查询
foreach (var a in query)
{
Console.WriteLine(a);
}

分析:首先遍历数组中的每个元素,然后用where语句筛选出小于5,并且对2去模是0的数查询出来返回。

where子句不仅能使用表达式来进行筛选,还可以使用方法进行筛选。

public static bool IsEven(int a)
{
return a % == ? true : false;
}
//数据源
int[] arr = { , , , , , , , , , }; //where子句也可以接受一个方法
var query = from a in arr
where IsEven(a)
select a; foreach (var a in query)
{
Console.Write(a + ",");
}

这就是一个在where语句中使用方法进行筛选的例子,输出的结果和上例完全一样。

使用where子句还要注意以下几点

  • 一个查询表达式可以包含多个where子句
  • where子句是一种筛选机制。除了不能是第一个或最后一个子句外,它几乎可以放在查询表达式中的任何位置。where子句可以出现在group子句的前面或后面,具体情况取决于是必须在对源元素进行分组之前还是分组之后来筛选源元素。
  • 如果指定的谓词对于数据源中的元素无效,则会发生编译时错误。这是Linq提供的强类型检查的一个优点。
  • 编译时,where关键字会被转换为对where标准查询运算符方法的调用。

orderby子句

适用场景:对查询出的语句进行排序,比如按时间排序等等。

说明:按指定表达式对集合排序;延迟,:按指定表达式对集合排序;延迟,默认是升序,加上descending表示降序,对应的扩展方法是OrderBy和OrderByDescending

  • 对查询出来的结果集进行升序或降序排列。
  • 可以指定多个键,以便执行一个或多个次要排序操作。
  • 默认排序顺序为升序。
  • 编译时,orderby子句将被转换为对OrderBy方法的调用。orderby子句中的多个键转换为ThenBy方法调用。

接着上个例子的演示,本例是一个升序的排序。

var query = from a in arr
where IsEven(a)
orderby a ascending
select a;

本例是一个降序的排序。

var query = from a in arr
where IsEven(a)
orderby a descending
select a;

1)简单形式

这个例子使用 orderby 按雇用日期对雇员进行排序:

var q =
from e in db.Employees
orderby e.HireDate
select e;

说明:默认为升序

2)带条件形式

注意:Where和Order By的顺序并不重要。而在T-SQL中,Where和Order By有严格的位置限制。

var q =
from o in db.Orders
where o.ShipCity == "London"
orderby o.Freight
select o;

语句描述:使用where和orderby按运费进行排序。

3)降序排序

var q =
from p in db.Products
orderby p.UnitPrice descending
select p;

4)ThenBy

语句描述:使用复合的 orderby 对客户进行排序,进行排序:

var q =
from c in db.Customers
orderby c.City, c.ContactName
select c;

说明:按多个表达式进行排序,例如先按City排序,当City相同时,按ContactName排序。这一句用Lambda表达式像这样写:

var q =
db.Customers
.OrderBy(c => c.City)
.ThenBy(c => c.ContactName).ToList();

在T-SQL中没有ThenBy语句,其依然翻译为OrderBy,所以也可以用下面语句来表达:

var q =
db.Customers
.OrderBy(c => c.ContactName)
.OrderBy(c => c.City).ToList();

所要注意的是,多个OrderBy操作时,级连方式是按逆序。 对于降序的,用相应的降序操作符替换即可。

var q =
db.Customers
.OrderByDescending(c => c.City)
.ThenByDescending(c => c.ContactName).ToList();

需要说明的是,OrderBy操作,不支持按type排序,也不支持匿名类。比如

var q =
db.Customers
.OrderBy(c => new
{
c.City,
c.ContactName
}).ToList();

会被抛出异常。错误是前面的操作有匿名类,再跟OrderBy时,比较的是类别。比如

var q =
db.Customers
.Select(c => new
{
c.City,
c.Address
})
.OrderBy(c => c).ToList();

如果你想使用OrderBy(c => c),其前提条件是,前面步骤中,所产生的对象的类别必须为C#语言的基本类型。比如下句,这里City为string类型。

var q =
db.Customers
.Select(c => c.City)
.OrderBy(c => c).ToList();

5)ThenByDescending

这两个扩展方式都是用在OrderBy/OrderByDescending之后的,第一个ThenBy/ThenByDescending扩展方法作为第二位排序依据,第二个ThenBy/ThenByDescending则作为第三位排序依据,以此类推

var q =
from o in db.Orders
where o.EmployeeID ==
orderby o.ShipCountry, o.Freight descending
select o;

语句描述:使用orderby先按发往国家再按运费从高到低的顺序对 EmployeeID 1 的订单进行排序。

6)带GroupBy形式

var q =
from p in db.Products
group p by p.CategoryID into g
orderby g.Key
select new {
g.Key,
MostExpensiveProducts =
from p2 in g
where p2.UnitPrice == g.Max(p3 => p3.UnitPrice)
select p2
};

语句描述:使用orderby、Max 和 Group By 得出每种类别中单价最高的产品,并按 CategoryID 对这组产品进行排序。

group子句

  • group子句返回一个IGrouping(T Key,T element)对象序列
  • 编译时,group子句被转换成对GroupBy方法的调用

需求:根据首字母分组,并打印到控制台

//数据源
string[] fruits = { "apple", "banana", "peach", "orange", "melon", "lemon" }; //分组查询的查询语句
var query = from f in fruits
group f by f[]; //执行查询
foreach (var letters in query)
{
Console.WriteLine("words that start with letter:" + letters.Key);
foreach (var word in letters)
{
Console.WriteLine(word);
}
}

分析:首先遍历字符串数组中的每个字符串,然后根据每个字符串的首字母进行分组,返回结果

var query = from f in fruits
group f by f[] into g
where g.Key == 'p' || g.Key == 'b'
select g;

如果您想要对每个组执行附加查询操作,则可以使用into上下文关键字指定一个临时标识符。使用into时,必须继续编写该查询,并最终用一个select语句或另一个group子句结束该查询。

join子句

  • 使用join子句可以将来自不同源序列并且在对象模型中没有直接关系的元素相关联。
  • 唯一的要求是每个源中的元素需要共享某个可以进行比较以判断是否相等的值。
  • join子句使用特殊的equals关键字比较指定的键是否相等。

1)内部连接

var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name };

2)分组连接

 var innerGroupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
into prodGroup
select new { CategoryName = category.Name, Products = prodGroup };

3)左外部连接

var leftOuterJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
into prodGroup
from item in prodGroup.DefaultIfEmpty(new Product{Name =
string.Empty, CategoryID = })
select new { CatName = category.Name, ProdName = item.Name };

在左外连接中,将返回左侧源序列中的所有元素,即使它们在右侧序列中没有匹配的元素也是如此。

若要在Linq中执行左外连接,请将DefaultIfEmpty方法与分组连接结合起来,以指定要在某个元素不具有匹配元素时产生的默认右侧元素,可以使用null作为任何引用类型的默认值。也可以指定用户定义的默认类型。

equals关键字

  • join子句执行同等连接。换句话说,只能基于两个键之间的相等关系进行匹配。
  • 为了表明所有连接都是同等连接,join子句使用equals关键字而不是==运算符

select子句(选择、投影)

select子句可以指定将在执行查询时产生的值的类型。该子句的结果将基于前面所有子句的计算结果以及select子句本身中的所有表达式。

查询表达式必须以select子句或group子句结束

在最简单的情况下,select子句仅指定范围变量。这会使返回的序列包含于数据源具有相同类型的元素。

Linq to SQL -- 入门篇的更多相关文章

  1. Linq To sql入门练习 Lambda表达式基础

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  2. Linq to SQL 基础篇

    LinqtoSqlDataContext Linq = new LinqtoSqlDataContext(ConfigurationManager.ConnectionStrings["sz ...

  3. IT咨询顾问:一次吐血的项目救火 java或判断优化小技巧 asp.net core Session的测试使用心得 【.NET架构】BIM软件架构02:Web管控平台后台架构 NetCore入门篇:(十一)NetCore项目读取配置文件appsettings.json 使用LINQ生成Where的SQL语句 js_jquery_创建cookie有效期问题_时区问题

    IT咨询顾问:一次吐血的项目救火   年后的一个合作公司上线了一个子业务系统,对接公司内部的单点系统.我收到该公司的技术咨询:项目启动后没有规律的突然无法登录了,重新启动后,登录一断时间后又无法重新登 ...

  4. [原创]Linq to xml增删改查Linq 入门篇:分分钟带你遨游Linq to xml的世界

    本文原始作者博客 http://www.cnblogs.com/toutou Linq 入门篇(一):分分钟带你遨游linq to xml的世界 本文原创来自博客园 请叫我头头哥的博客, 请尊重版权, ...

  5. 讲讲Linq to SQL映射(基础篇)

    讲讲Linq to SQL映射(基础篇) 这篇主要讲Linq to  SQL基于属性的映射.即映射数据库,映射表,映射列,映射关系,映射存储过程, 映射函数.然而创建这种映射有三种方法,他们分别是OR ...

  6. 新注册第一帖----------------------乱码新手自学.net 之Linq 入门篇

    作为一个业余开发,断断续续学.net/c#也有不少日子了, 学习过程中,不断忘了学,学了忘,这让我很苦恼. 以前学习过程中,我总是在笔记本中记录下来知识要点,这么久下来,笔记本都写了四五本了. 然而, ...

  7. SQL注入攻击三部曲之入门篇

    SQL注入攻击三部曲之入门篇 服务器安全管理员和攻击者的战争仿佛永远没有停止的时候,针对国内网站的ASP架构的SQL注入攻击又开始大行其道.本篇文章通过SQL注入攻击原理引出SQL注入攻击的实施方法, ...

  8. LinQ实战学习笔记(一) LINQ to (Objects, XML, SQL) 入门初步

    LINQ对于笔者来说, 优美而浓缩的代码让人震惊. 研究LINQ就是在艺术化自己的代码. 之前只是走马观花学会了基本的语法, 但是经常在CSDN看到令人惊讶自叹不如的LINQ代码, 还是让人羡慕嫉妒恨 ...

  9. Linq To Sql进阶系列(六)用object的动态查询与保存log篇

    动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...

随机推荐

  1. 前端框架Angular、react、vue在github上的数据统计-2018-05

    2018年5月31日09:15:45 突然想看看几个前端框架的数量,然后就截图了如下数据: 分析: react关注.收藏.Fork都高vue一些, 但相差不大 angular比较奇葩,收藏只有二者一半 ...

  2. MySQL-8.0.11与Navicat Premium安装教程

    1. 下载MySQL 下载地址: https:////dev.mysql.com/downloads/mysql/ 百度云 链接:https://pan.baidu.com/s/1bxAtnvChZZ ...

  3. 内联元素padding与高度可控的分隔线实例页面

    html: <a href="">登录</a><a href="">注册</a> css: a + a:befo ...

  4. Java基础知识学习思维导图

  5. spring3-struts2整合

    spring  负责对象创建 struts   用Action处理请求 说明: spring版本:spring-framework-3.2.5.RELEASE struts版本:struts-2.3. ...

  6. XSS学习(三)挖掘思路

    HTML标签之间 <div id="body"> [输出点] </div> payload:<script>alert(1)</scrip ...

  7. 终于懂得Perl句柄是什么意思了

    一直以来就对Perl语言特别感兴趣,去年特别膨胀的 直接买了一本大骆驼书,想好好看看Perl编程,结果看到I/O,句柄的时候就觉得云山雾罩,不知道是在说啥了, 最近,京东打折,终于有机会又买了本小骆驼 ...

  8. 30天学会绘画 (Mark Kistler 著)

    第一课 球形 (已看) 第二课 重叠的球 (已看) 第三课 更多排列的球 (已看) 第四课 立方体 (已看) 第五课 空心立方体 (已看) 第六课 堆放的桌子 (已看) 第七课 堆放更多的立方体 (已 ...

  9. 为s5pv210烧录镜像

    1.使用九鼎提供的工具,在sd卡中烧录uboot 2.重启开发板,进入uboot命令行, fdisk -c 0 fastboot 3.电脑安装fastboot驱动 fastboot烧录镜像

  10. 通过localhost访问和通过IP地址访问页面CSS样式不一样

    在开发ICT项目管理系统时,发现在开发环境下看到的页面和在部署环境下看到的页面不一样.开发环境下看到的页面比较舒服,部署后看到的页面比较生涩.究其原因,发现地址栏里面一个是localhost,一个是I ...