【转】 LINQ TO SQL中的selectMany
2010-02-28 11:34 AnyKoro 阅读(473) 评论(0) 编辑 收藏 举报首先看SelectMany的定义:
Queryable中的SelectMany 方法:将序列的每个元素投影到一个 IEnumerable<(Of <(T>)>) 并将结果序列组合为一个 IQueryable<(Of <(T>)>) 类型的序列。(引用MSDN)
在用LINQ TO SQL 来写查询语句时,有一个selectMany的语句,它标示着一对多的关系,这篇文章我想说下在LINQ TO SQL中几种可以等同selectMany的用法。
系统转换成selectMany的条件:
1:语句中不包含join ,into;
2:需要2个以上的from:下面以两个表为例:如第一个表from c in 表1
1):如果from的对象均用表名,(from c in 表2),则会转换成cross join;
2):如果第二个表名以第一个表的子表形式出现,即类似c.表2,这又分两种情况,
1>:from o in c.表2,此时会形成inner join
2>:from p in c.表2.DefaultIfEmpty(),此时会形成LEFT OUT JOIN
文中例子表结构说明:Customer表和Purchase表,通过ID与CustomerID建立关联。
- CREATE TABLE [dbo].[Customer](
- [ID] [int] NOT NULL,
- [Name] [nvarchar](30) )
- CREATE TABLE [dbo].[Purchase](
- [ID] [int] NOT NULL,
- [CustomerID] [int] NULL,
- [Date] [datetime] NOT NULL,
- [Description] [varchar](30) )
我们来实现SQL中的三种非常经典的联接方式。
第一:cross join,它的结果集是所有表的迪卡尔积。
- //cross join
- from c in Customers
- from o in Purchases
- select o
在LINQ TO SQL中,下面的from都指定为表名的话,就会生成下面的语句:
- SELECT [t1].[ID], [t1].[CustomerID], [t1].[Date], [t1].[Description], [t1].[Price]
- FROM [Customer] AS [t0], [Purchase] AS [t1]
第二:inner join。
- //inner join
- from c in Customers
- from o in c.Purchases
- select o
生成的SQL如下:
- SELECT [t1].[ID], [t1].[CustomerID], [t1].[Date], [t1].[Description], [t1].[Price]
- FROM [Customer] AS [t0], [Purchase] AS [t1]
- WHERE [t1].[CustomerID] = [t0].[ID]
虽然没有显示的用inner join,但和它的功能是一样的.它的写法和上面的cross join看起来特别像,唯一的区别就在于cross join时,直接用了表名Purchases,而inner join用的时候变成了c.Pruchasex,即形成了一对多的情况。
第三: LEFT OUTER JOIN
- from c in Customers
- from p in c.Purchases.DefaultIfEmpty()
- select new { c.Name, p.Description, Price = (decimal?) p.Price }
生成的SQL如下:
- SELECT [t0].[Name], [t1].[Description] AS [Description], [t1].[Price] AS [Price]
- FROM [Customer] AS [t0]
- LEFT OUTER JOIN [Purchase] AS [t1] ON [t1].[CustomerID] = [t0].[ID]
left outer join实际上是在inner join的基础上加了一个条件,利用DefaultIfEmpty(),当记录不匹配时,返回null
我们对上在的查询增加一个过滤条件。
- from c in Customers
- from p in c.Purchases.Where (p => p.Price > 1000).DefaultIfEmpty()
- select new
- {
- c.Name,
- p.Description,
- Price = (decimal?) p.Price
- }
对应的SQL:
- SELECT [t0].[Name], [t1].[Description] AS [Description], [t1].[Price] AS [Price]
- FROM [Customer] AS [t0]
- LEFT OUTER JOIN [Purchase] AS [t1] ON ([t1].[Price] > @p0) AND ([t1].[CustomerID] = [t0].[ID])
此时上面的语句还是标准的LEFT OUT JOIN,如果我们改变下条件的位置呢?
- from c in Customers
- from p in c.Purchases.DefaultIfEmpty()
- where p.Price>1000
- select new
- {
- c.Name,
- p.Description,
- Price = (decimal?) p.Price
- }
对应的SQL:
- SELECT [t0].[Name], [t1].[Description] AS [Description], [t1].[Price] AS [Price]
- FROM [Customer] AS [t0]
- LEFT OUTER JOIN [Purchase] AS [t1] ON [t1].[CustomerID] = [t0].[ID]
- WHERE [t1].[Price] > @p0
条件改变位置后并没有改变join的本质,还是LEFT OUT JOIN,只不过查询的结果不一样了,从结果集上看,后面一种的效果和inner join的结果一样。
总结:上面的查询语句也可以用显示的join来查询,个人更喜欢用显示的join,因为相比较SQL更接近些,看起来要亲近些。在下篇文章中,我会总结显示用join查询的用法,其实最终的显示结果都一样,只是写法不同。
文/姜敏 出处/博客园
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)