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):

  1. var q =
  2. from c in db.Customers
  3. from o in c.Orders
  4. where c.City == "London"
  5. select o;

语句描述:Customers与Orders是一对多关系。即Orders在Customers类中以EntitySet形式出现。所以第二个from是 从c.Orders而不是db.Orders里进行筛选。这个例子在From子句中使用外键导航选择伦敦客户的所有订单。

  1. var q =
  2. from p in db.Products
  3. where p.Supplier.Country == "USA" && p.UnitsInStock == 0
  4. select p;

语句描述:这一句使用了p.Supplier.Country条件,间接关联了Supplier表。这个例子在Where子句中使用外键导航筛选其供应商在美国且缺货的产品。生成SQL语句为:

  1. SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID],
  2. [t0].[CategoryID],[t0].[QuantityPerUnit],[t0].[UnitPrice],
  3. [t0].[UnitsInStock], [t0].[UnitsOnOrder],[t0].[ReorderLevel],
  4. [t0].[Discontinued] FROM [dbo].[Products] AS [t0]
  5. LEFT OUTER JOIN [dbo].[Suppliers] AS [t1] ON
  6. [t1].[SupplierID] = [t0].[SupplierID]
  7. WHERE ([t1].[Country] = @p0) AND ([t0].[UnitsInStock] = @p1)
  8. -- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [USA]
  9. -- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [0]

2.多对多关系(Many to Many):

  1. var q =
  2. from e in db.Employees
  3. from et in e.EmployeeTerritories
  4. where e.City == "Seattle"
  5. select new
  6. {
  7. e.FirstName,
  8. e.LastName,
  9. et.Territory.TerritoryDescription
  10. };

说明:多对多关系一般会涉及三个表(如果有一个表是自关联的,那有可能只有2个表)。这一句语句涉及Employees, EmployeeTerritories, Territories三个表。它们的关系是1:M:1。Employees和Territories没有很明确的关系。

语句描述:这个例子在From子句中使用外键导航筛选在西雅图的雇员,同时列出其所在地区。这条生成SQL语句为:

  1. SELECT [t0].[FirstName], [t0].[LastName], [t2].[TerritoryDescription]
  2. FROM [dbo].[Employees] AS [t0] CROSS JOIN [dbo].[EmployeeTerritories]
  3. AS [t1] INNER JOIN [dbo].[Territories] AS [t2] ON
  4. [t2].[TerritoryID] = [t1].[TerritoryID]
  5. WHERE ([t0].[City] = @p0) AND ([t1].[EmployeeID] = [t0].[EmployeeID])
  6. -- @p0: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [Seattle]

3.自联接关系:

  1. var q =
  2. from e1 in db.Employees
  3. from e2 in e1.Employees
  4. where e1.City == e2.City
  5. select new {
  6. FirstName1 = e1.FirstName, LastName1 = e1.LastName,
  7. FirstName2 = e2.FirstName, LastName2 = e2.LastName,
  8. e1.City
  9. };

语句描述:这个例子在select 子句中使用外键导航筛选成对的雇员,每对中一个雇员隶属于另一个雇员,且两个雇员都来自相同城市。生成SQL语句为:

  1. SELECT [t0].[FirstName] AS [FirstName1], [t0].[LastName] AS
  2. [LastName1],[t1].[FirstName] AS [FirstName2], [t1].[LastName] AS
  3. [LastName2],[t0].[City] FROM [dbo].[Employees] AS [t0],
  4. [dbo].[Employees] AS [t1] WHERE ([t0].[City] = [t1].[City]) AND
  5. ([t1].[ReportsTo] = [t0].[EmployeeID])

GroupJoin

像上面所说的,没有join和into,被翻译成SelectMany,同时有join和into时,那么就被翻译为GroupJoin。在这里into的概念是对其结果进行重新命名。

1.双向联接(Two way join):

此示例显式联接两个表并从这两个表投影出结果:

  1. var q =
  2. from c in db.Customers
  3. join o in db.Orders on c.CustomerID
  4. equals o.CustomerID into orders
  5. select new
  6. {
  7. c.ContactName,
  8. OrderCount = orders.Count()
  9. };

说明:在一对多关系中,左边是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返回值作为字段值

  1. SELECT [t0].[ContactName], (
  2. SELECT COUNT(*)
  3. FROM [dbo].[Orders] AS [t1]
  4. WHERE [t0].[CustomerID] = [t1].[CustomerID]
  5. ) AS [OrderCount]
  6. FROM [dbo].[Customers] AS [t0]

2.三向联接(There way join):

此示例显式联接三个表并分别从每个表投影出结果:

  1. var q =
  2. from c in db.Customers
  3. join o in db.Orders on c.CustomerID
  4. equals o.CustomerID into ords
  5. join e in db.Employees on c.City
  6. equals e.City into emps
  7. select new
  8. {
  9. c.ContactName,
  10. ords = ords.Count(),
  11. emps = emps.Count()
  12. };

生成SQL语句为:

  1. SELECT [t0].[ContactName], (
  2. SELECT COUNT(*)
  3. FROM [dbo].[Orders] AS [t1]
  4. WHERE [t0].[CustomerID] = [t1].[CustomerID]
  5. ) AS [ords], (
  6. SELECT COUNT(*)
  7. FROM [dbo].[Employees] AS [t2]
  8. WHERE [t0].[City] = [t2].[City]
  9. ) AS [emps]
  10. FROM [dbo].[Customers] AS [t0]

3.左外部联接(Left Outer Join):

此示例说明如何通过使用DefaultIfEmpty() 获取左外部联接。在雇员没有订单时,DefaultIfEmpty()方法返回null:

  1. var q =
  2. from e in db.Employees
  3. join o in db.Orders on e equals o.Employee into ords
  4. from o in ords.DefaultIfEmpty()
  5. select new
  6. {
  7. e.FirstName,
  8. e.LastName,
  9. Order = o
  10. };

说明:以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”表达式:

  1. var q =
  2. from c in db.Customers
  3. join o in db.Orders on c.CustomerID
  4. equals o.CustomerID into ords
  5. let z = c.City + c.Country
  6. from o in ords
  7. select new
  8. {
  9. c.ContactName,
  10. o.OrderID,
  11. z
  12. };

5.组合键(Composite Key):

这个例子显示带有组合键的联接:

  1. var q =
  2. from o in db.Orders
  3. from p in db.Products
  4. join d in db.OrderDetails
  5. on new
  6. {
  7. o.OrderID,
  8. p.ProductID
  9. } equals
  10. new
  11. {
  12. d.OrderID,
  13. d.ProductID
  14. }
  15. into details
  16. from d in details
  17. select new
  18. {
  19. o.OrderID,
  20. p.ProductID,
  21. d.UnitPrice
  22. };

equals也就是比较引用类型是否是对同一个对象的引用。  

说明:使用三个表,并且用匿名类来表示它们之间的关系。它们之间的关系不能用一个键描述清楚,所以用匿名类,来表示组合键。还有一种是两个表之间是用组合键表示关系的,不需要使用匿名类。

6.可为null/不可为null的键关系(Nullable/Nonnullable Key Relationship):

这个实例显示如何构造一侧可为 null 而另一侧不可为 null 的联接:

  1. var q =
  2. from o in db.Orders
  3. join e in db.Employees
  4. on o.EmployeeID equals
  5. (int?)e.EmployeeID into emps
  6. from e in emps
  7. select new
  8. {
  9. o.OrderID,
  10. e.FirstName
  11. };

  Order By操作

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

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

1.简单形式

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

  1. var q =
  2. from e in db.Employees
  3. orderby e.HireDate
  4. select e;

说明:默认为升序

2.带条件形式

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

  1. var q =
  2. from o in db.Orders
  3. where o.ShipCity == "London"
  4. orderby o.Freight
  5. select o;

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

3.降序排序

  1. var q =
  2. from p in db.Products
  3. orderby p.UnitPrice descending
  4. select p;

4.ThenBy

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

  1. var q =
  2. from c in db.Customers
  3. orderby c.City, c.ContactName
  4. select c;

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

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

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

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

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

  1. var q =
  2. db.Customers
  3. .OrderBy(c => new
  4. {
  5. c.City,
  6. c.ContactName
  7. }).ToList();

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

  1. var q =
  2. db.Customers
  3. .Select(c => new
  4. {
  5. c.City,
  6. c.Address
  7. })
  8. .OrderBy(c => c).ToList();

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

  1. var q =
  2. db.Customers
  3. .Select(c => c.City)
  4. .OrderBy(c => c).ToList();

5.ThenByDescending

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

  1. var q =
  2. from o in db.Orders
  3. where o.EmployeeID == 1
  4. orderby o.ShipCountry, o.Freight descending
  5. select o;

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

6.带GroupBy形式

  1. var q =
  2. from p in db.Products
  3. group p by p.CategoryID into g
  4. orderby g.Key
  5. select new {
  6. g.Key,
  7. MostExpensiveProducts =
  8. from p2 in g
  9. where p2.UnitPrice == g.Max(p3 => p3.UnitPrice)
  10. select p2
  11. };

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

LINQ学习之旅(三)的更多相关文章

  1. Hadoop学习之旅三:MapReduce

    MapReduce编程模型 在Google的一篇重要的论文MapReduce: Simplified Data Processing on Large Clusters中提到,Google公司有大量的 ...

  2. 滴滴Booster移动APP质量优化框架 学习之旅 三

    推荐阅读: 滴滴Booster移动App质量优化框架-学习之旅 一 Android 模块Api化演练 不一样视角的Glide剖析(一) 滴滴Booster移动App质量优化框架-学习之旅 二对重复资源 ...

  3. Linq学习之旅——LINQ查询表达式

    1. 概述 2. from子句 3. where子句 4. select子句 5. group子句 6. into子句 7. 排序子句 8. let子句 9. join子句 10. 小结 1. 概述 ...

  4. LINQ学习之旅 (四)

    LINQ to SQL语句之Group By/Having和Exists/In/Any/All/Contains 1.Group By/Having操作符 适用场景:分组数据,为我们查找数据缩小范围. ...

  5. LINQ学习之旅(二)

    一:查询表达式(LINQ)简介 LINQ是Language Integrated Query的简称,它是集成在.NET编程语言中的一种特性.已成为编程语言的一个组成部分,在编写程序时可以得到很好的编译 ...

  6. Spring学习之旅(三)--装配Bean

    装配 Bean 的方式 在 XML 中进行显式配置 在 Java 中进行显式配置 隐式的 Bean 发现机制和自动装配 Spring 提供了以上三种方式进行 Bean 的配置,可以根据自己的需求选择一 ...

  7. struts2学习之旅三 权限管理和导航设计

    1,权限管理的db设计和dao实现,尽量简单快速有效: db的设计如下:权限按照角色来赋给用户: 权限对应每一个具体的功能,有菜单级别的,有导航级别的,还有页面级别的功能: 涉及到权限的敏感操作一般都 ...

  8. LINQ学习之旅(六)

    Insert/Update/Delete操作 插入(Insert) 1.简单形式 说明:new一个对象,使用InsertOnSubmit方法将其加入到对应的集合中,使用SubmitChanges()提 ...

  9. LINQ学习之旅(五)

    Union All/Union/Intersect操作和Top/Bottom操作和Paging操作和SqlMethods操作 Union All/Union/Intersect操作 适用场景:对两个集 ...

随机推荐

  1. Spring 学习03

    一.上节内容回顾 1 注解ioc操作 (1)使用注解创建对象 - 四个注解 (2)使用注解注入属性 - 两个注解 2 aop (1)aop原理 (2)aop术语 - 切入点 - 增强 - 切面 3 s ...

  2. 20155332 2016-2017-2 《Java程序设计》第9周学习总结

    20155332 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 了解JDBC架构 掌握JDBC架构 掌握反射与ClassLoader 了解自定义泛型和自定义 ...

  3. [C++]指针与引用(应用辨析)

    1.指针变量允许将一个整数经强制转换后赋值给指针变量    Eg:      float *fp;      fp = (float *)5000;//意义:将5000作为一个地址赋给指针变量fp 2 ...

  4. android 基础题

    1. Android的四大组件是哪些,它们的作用? (1).Activity:Activity是Android程序与用户交互的窗口,是Android构造块中最基本的一种,它需要为保持各界面的状态,做很 ...

  5. Struts S2-052漏洞利用

    昨天在FreeBuf上看到[9月6日更新]漏洞预警 | 高危Struts REST插件远程代码执行漏洞(S2-052) 然而一直复现不了,今天又试了下竟然成功了. 由于水表查的较严,就不冒险搞别人的服 ...

  6. 用struts2 s2-045漏洞拿站记录

    浏览FreeBuf时发现的文章,新出的漏洞: http://www.freebuf.com/vuls/128668.html 漏洞一出,各位大神早就写出POC: http://www.reg008.c ...

  7. Docker安装Zookeeper

    ⒈下载 docker pull zookeeper ⒉运行 docker run --name zk -p 2181:2181 -p 2888:2888 -p 3888:3888 --restart ...

  8. Windows和Mac上NodeJS和Express的安装

    一.安装NodeJS,官网上下载,https://nodejs.org/en/ 直接下一步安装就行了. 打开命令行工具,输入 node -v 则会出现node的版本,则成功了. 下面我们介绍如何安装e ...

  9. Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历))

    Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历)) 本文由 Luzhuo 编写,转发请保留该信息. 原文: http://blog. ...

  10. mysql系列十一、mysql优化笔记:表设计、sql优化、配置优化

    可以从这些方面进行优化: 数据库(表)设计合理 SQL语句优化 数据库配置优化 系统层.硬件层优化 数据库设计 关系数据库三范式 1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非 ...