LINQ学习之旅(三)
Linq to Sql语句之Join和Order By
Join操作
适用场景:在我们表关系中有一对一关系,一对多关系,多对多关系等。对各个表之间的关系,就用这些实现对多个表的操作。
说明:在Join操作中,分别为Join(Join查询), SelectMany(Select一对多选择)和GroupJoin(分组Join查询)。
该扩展方法对两个序列中键匹配的元素进行inner join操作
SelectMany
说明:我们在写查询语句时,如果被翻译成SelectMany需要满足2个条件。1:查询语句中没有join和into,2:必须出现EntitySet。在我们表关系中有一对一关系,一对多关系,多对多关系等,下面分别介绍一下。
1.一对多关系(1 to Many):
- var q =
- from c in db.Customers
- from o in c.Orders
- where c.City == "London"
- select o;
语句描述:Customers与Orders是一对多关系。即Orders在Customers类中以EntitySet形式出现。所以第二个from是 从c.Orders而不是db.Orders里进行筛选。这个例子在From子句中使用外键导航选择伦敦客户的所有订单。
- var q =
- from p in db.Products
- where p.Supplier.Country == "USA" && p.UnitsInStock == 0
- select p;
语句描述:这一句使用了p.Supplier.Country条件,间接关联了Supplier表。这个例子在Where子句中使用外键导航筛选其供应商在美国且缺货的产品。生成SQL语句为:
- SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID],
- [t0].[CategoryID],[t0].[QuantityPerUnit],[t0].[UnitPrice],
- [t0].[UnitsInStock], [t0].[UnitsOnOrder],[t0].[ReorderLevel],
- [t0].[Discontinued] FROM [dbo].[Products] AS [t0]
- LEFT OUTER JOIN [dbo].[Suppliers] AS [t1] ON
- [t1].[SupplierID] = [t0].[SupplierID]
- WHERE ([t1].[Country] = @p0) AND ([t0].[UnitsInStock] = @p1)
- -- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [USA]
- -- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [0]
2.多对多关系(Many to Many):
- var q =
- from e in db.Employees
- from et in e.EmployeeTerritories
- where e.City == "Seattle"
- select new
- {
- e.FirstName,
- e.LastName,
- et.Territory.TerritoryDescription
- };
说明:多对多关系一般会涉及三个表(如果有一个表是自关联的,那有可能只有2个表)。这一句语句涉及Employees, EmployeeTerritories, Territories三个表。它们的关系是1:M:1。Employees和Territories没有很明确的关系。
语句描述:这个例子在From子句中使用外键导航筛选在西雅图的雇员,同时列出其所在地区。这条生成SQL语句为:
- SELECT [t0].[FirstName], [t0].[LastName], [t2].[TerritoryDescription]
- FROM [dbo].[Employees] AS [t0] CROSS JOIN [dbo].[EmployeeTerritories]
- AS [t1] INNER JOIN [dbo].[Territories] AS [t2] ON
- [t2].[TerritoryID] = [t1].[TerritoryID]
- WHERE ([t0].[City] = @p0) AND ([t1].[EmployeeID] = [t0].[EmployeeID])
- -- @p0: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [Seattle]
3.自联接关系:
- var q =
- from e1 in db.Employees
- from e2 in e1.Employees
- where e1.City == e2.City
- select new {
- FirstName1 = e1.FirstName, LastName1 = e1.LastName,
- FirstName2 = e2.FirstName, LastName2 = e2.LastName,
- e1.City
- };
语句描述:这个例子在select 子句中使用外键导航筛选成对的雇员,每对中一个雇员隶属于另一个雇员,且两个雇员都来自相同城市。生成SQL语句为:
- SELECT [t0].[FirstName] AS [FirstName1], [t0].[LastName] AS
- [LastName1],[t1].[FirstName] AS [FirstName2], [t1].[LastName] AS
- [LastName2],[t0].[City] FROM [dbo].[Employees] AS [t0],
- [dbo].[Employees] AS [t1] WHERE ([t0].[City] = [t1].[City]) AND
- ([t1].[ReportsTo] = [t0].[EmployeeID])
GroupJoin
像上面所说的,没有join和into,被翻译成SelectMany,同时有join和into时,那么就被翻译为GroupJoin。在这里into的概念是对其结果进行重新命名。
1.双向联接(Two way join):
此示例显式联接两个表并从这两个表投影出结果:
- var q =
- from c in db.Customers
- join o in db.Orders on c.CustomerID
- equals o.CustomerID into orders
- select new
- {
- c.ContactName,
- OrderCount = orders.Count()
- };
说明:在一对多关系中,左边是1,它每条记录为c(from c in db.Customers),右边是Many,其每条记录叫做o ( join o in db.Orders ),每对应左边的一个c,就会有一组o,那这一组o,就叫做orders,也就是说,我们把一组o命名为orders,这就是into用途。这也就是为什 么在select语句中,orders可以调用聚合函数Count。在T-SQL中,使用其内嵌的T-SQL返回值作为字段值
- SELECT [t0].[ContactName], (
- SELECT COUNT(*)
- FROM [dbo].[Orders] AS [t1]
- WHERE [t0].[CustomerID] = [t1].[CustomerID]
- ) AS [OrderCount]
- FROM [dbo].[Customers] AS [t0]
2.三向联接(There way join):
此示例显式联接三个表并分别从每个表投影出结果:
- var q =
- from c in db.Customers
- join o in db.Orders on c.CustomerID
- equals o.CustomerID into ords
- join e in db.Employees on c.City
- equals e.City into emps
- select new
- {
- c.ContactName,
- ords = ords.Count(),
- emps = emps.Count()
- };
生成SQL语句为:
- SELECT [t0].[ContactName], (
- SELECT COUNT(*)
- FROM [dbo].[Orders] AS [t1]
- WHERE [t0].[CustomerID] = [t1].[CustomerID]
- ) AS [ords], (
- SELECT COUNT(*)
- FROM [dbo].[Employees] AS [t2]
- WHERE [t0].[City] = [t2].[City]
- ) AS [emps]
- FROM [dbo].[Customers] AS [t0]
3.左外部联接(Left Outer Join):
此示例说明如何通过使用DefaultIfEmpty() 获取左外部联接。在雇员没有订单时,DefaultIfEmpty()方法返回null:
- var q =
- from e in db.Employees
- join o in db.Orders on e equals o.Employee into ords
- from o in ords.DefaultIfEmpty()
- select new
- {
- e.FirstName,
- e.LastName,
- Order = o
- };
说明:以Employees左表,Orders右表,Orders 表中为空时,用null值填充。Join的结果重命名ords,使用DefaultIfEmpty()函数对其再次查询。其最后的结果中有个Order,因为from o in ords.DefaultIfEmpty() 是对ords组再一次遍历,所以,最后结果中的Order并不是一个集合。但是,如果没有from o in ords.DefaultIfEmpty() 这句,最后的select语句写成select new { e.FirstName, e.LastName, Order = ords }的话,那么Order就是一个集合。
4.投影的Let赋值(Projected let assignment):
说明: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
- };
5.组合键(Composite Key):
这个例子显示带有组合键的联接:
- var q =
- from o in db.Orders
- from p in db.Products
- join d in db.OrderDetails
- on new
- {
- o.OrderID,
- p.ProductID
- } equals
- new
- {
- d.OrderID,
- d.ProductID
- }
- into details
- from d in details
- select new
- {
- o.OrderID,
- p.ProductID,
- d.UnitPrice
- };
equals也就是比较引用类型是否是对同一个对象的引用。
说明:使用三个表,并且用匿名类来表示它们之间的关系。它们之间的关系不能用一个键描述清楚,所以用匿名类,来表示组合键。还有一种是两个表之间是用组合键表示关系的,不需要使用匿名类。
6.可为null/不可为null的键关系(Nullable/Nonnullable Key Relationship):
这个实例显示如何构造一侧可为 null 而另一侧不可为 null 的联接:
- var q =
- from o in db.Orders
- join e in db.Employees
- on o.EmployeeID equals
- (int?)e.EmployeeID into emps
- from e in emps
- select new
- {
- o.OrderID,
- e.FirstName
- };
Order By操作
适用场景:对查询出的语句进行排序,比如按时间排序等等。
说明:按指定表达式对集合排序;延迟,:按指定表达式对集合排序;延迟,默认是升序,加上descending表示降序,对应的扩展方法是OrderBy和OrderByDescending
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();
所要注意的是,多个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 == 1
- 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 对这组产品进行排序
LINQ学习之旅(三)的更多相关文章
- Hadoop学习之旅三:MapReduce
MapReduce编程模型 在Google的一篇重要的论文MapReduce: Simplified Data Processing on Large Clusters中提到,Google公司有大量的 ...
- 滴滴Booster移动APP质量优化框架 学习之旅 三
推荐阅读: 滴滴Booster移动App质量优化框架-学习之旅 一 Android 模块Api化演练 不一样视角的Glide剖析(一) 滴滴Booster移动App质量优化框架-学习之旅 二对重复资源 ...
- Linq学习之旅——LINQ查询表达式
1. 概述 2. from子句 3. where子句 4. select子句 5. group子句 6. into子句 7. 排序子句 8. let子句 9. join子句 10. 小结 1. 概述 ...
- LINQ学习之旅 (四)
LINQ to SQL语句之Group By/Having和Exists/In/Any/All/Contains 1.Group By/Having操作符 适用场景:分组数据,为我们查找数据缩小范围. ...
- LINQ学习之旅(二)
一:查询表达式(LINQ)简介 LINQ是Language Integrated Query的简称,它是集成在.NET编程语言中的一种特性.已成为编程语言的一个组成部分,在编写程序时可以得到很好的编译 ...
- Spring学习之旅(三)--装配Bean
装配 Bean 的方式 在 XML 中进行显式配置 在 Java 中进行显式配置 隐式的 Bean 发现机制和自动装配 Spring 提供了以上三种方式进行 Bean 的配置,可以根据自己的需求选择一 ...
- struts2学习之旅三 权限管理和导航设计
1,权限管理的db设计和dao实现,尽量简单快速有效: db的设计如下:权限按照角色来赋给用户: 权限对应每一个具体的功能,有菜单级别的,有导航级别的,还有页面级别的功能: 涉及到权限的敏感操作一般都 ...
- LINQ学习之旅(六)
Insert/Update/Delete操作 插入(Insert) 1.简单形式 说明:new一个对象,使用InsertOnSubmit方法将其加入到对应的集合中,使用SubmitChanges()提 ...
- LINQ学习之旅(五)
Union All/Union/Intersect操作和Top/Bottom操作和Paging操作和SqlMethods操作 Union All/Union/Intersect操作 适用场景:对两个集 ...
随机推荐
- Spring 学习03
一.上节内容回顾 1 注解ioc操作 (1)使用注解创建对象 - 四个注解 (2)使用注解注入属性 - 两个注解 2 aop (1)aop原理 (2)aop术语 - 切入点 - 增强 - 切面 3 s ...
- 20155332 2016-2017-2 《Java程序设计》第9周学习总结
20155332 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 了解JDBC架构 掌握JDBC架构 掌握反射与ClassLoader 了解自定义泛型和自定义 ...
- [C++]指针与引用(应用辨析)
1.指针变量允许将一个整数经强制转换后赋值给指针变量 Eg: float *fp; fp = (float *)5000;//意义:将5000作为一个地址赋给指针变量fp 2 ...
- android 基础题
1. Android的四大组件是哪些,它们的作用? (1).Activity:Activity是Android程序与用户交互的窗口,是Android构造块中最基本的一种,它需要为保持各界面的状态,做很 ...
- Struts S2-052漏洞利用
昨天在FreeBuf上看到[9月6日更新]漏洞预警 | 高危Struts REST插件远程代码执行漏洞(S2-052) 然而一直复现不了,今天又试了下竟然成功了. 由于水表查的较严,就不冒险搞别人的服 ...
- 用struts2 s2-045漏洞拿站记录
浏览FreeBuf时发现的文章,新出的漏洞: http://www.freebuf.com/vuls/128668.html 漏洞一出,各位大神早就写出POC: http://www.reg008.c ...
- Docker安装Zookeeper
⒈下载 docker pull zookeeper ⒉运行 docker run --name zk -p 2181:2181 -p 2888:2888 -p 3888:3888 --restart ...
- Windows和Mac上NodeJS和Express的安装
一.安装NodeJS,官网上下载,https://nodejs.org/en/ 直接下一步安装就行了. 打开命令行工具,输入 node -v 则会出现node的版本,则成功了. 下面我们介绍如何安装e ...
- Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历))
Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历)) 本文由 Luzhuo 编写,转发请保留该信息. 原文: http://blog. ...
- mysql系列十一、mysql优化笔记:表设计、sql优化、配置优化
可以从这些方面进行优化: 数据库(表)设计合理 SQL语句优化 数据库配置优化 系统层.硬件层优化 数据库设计 关系数据库三范式 1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非 ...