Linq to sql 结合Entity Framework 的连接查询总结
最近在做项目使用linq结合EntityFramework来处理数据库的操作。想来也用了快一年了,发现有些使用技巧是需要注意下,特做下总结,希望对刚入门的朋友们有所帮助。刚开始用的时候各总循环查询子查询,结果性能差得不行,现在看看都觉得好笑。也只有写出过很烂的代码才知道怎么样的代码才是优雅的吧,哈哈。我先总结下连接查询吧,发现很多刚入门的朋友和我一样,不知道怎么用linq写类似与sql的连接查询(left join、inner join等等)。
连接查询
-
内连接查询
linq语法如下:
1 var res = from a in sys.Apple 2 join b in sys.Banana 3 on a.Id equals b.AppleId 4 select new { 5 a.Id, 6 a.Name 7 };
直接写join就是内连接查询,我们来看看它生产的sql语句就明白为什么这是内连接了。
生成的sql如下:
SELECT 1 AS [C1], [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name] FROM [dbo].[apple] AS [Extent1] INNER JOIN [dbo].[banana] AS [Extent2] ON [Extent1].[Id] = [Extent2].[AppleId]
-
左连接、右连接
左连接linq语法如下:
1 var res = from a in sys.Apple 2 join b in sys.Banana 3 on a.Id equals b.AppleId into b1 4 select new { 5 a.Id, 6 a.Name, 7 Bananas = b1 8 };
这里的关键在于第7行的集合赋值哦,EF会根据你需要查询的结果生成相应的sql语句。
来看下生成的sql语句吧:
SELECT [Project1].[C1] AS [C1], [Project1].[Id] AS [Id], [Project1].[Name] AS [Name], [Project1].[C2] AS [C2], [Project1].[Id1] AS [Id1], [Project1].[Name1] AS [Name1], [Project1].[AppleId] AS [AppleId], [Project1].[comment] AS [comment] FROM ( SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], 1 AS [C1], [Extent2].[Id] AS [Id1], [Extent2].[Name] AS [Name1], [Extent2].[AppleId] AS [AppleId], [Extent2].[comment] AS [comment], CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2] FROM [dbo].[apple] AS [Extent1] LEFT OUTER JOIN [dbo].[banana] AS [Extent2] ON [Extent1].[Id] = [Extent2].[AppleId] ) AS [Project1] ORDER BY [Project1].[Id] ASC, [Project1].[C2] ASC
这个查询的结果会是一个对象包含b1结合,而不是sql的查询到的连接后的临时表结果。这里是EF自动帮我们把数据整理这样的形式了。在查询一对多的表数据时是很有用的哦。当然也可以用导航属性啦。
来看看另一形式的左连接吧
linq语法如下:
1 var res = from a in sys.Apple 2 join b in sys.Banana 3 on a.Id equals b.AppleId into b1 4 from b2 in b1.DefaultIfEmpty() 5 select new { 6 a.Id, 7 a.Name, 8 t = b2.AppleId 9 };
生成的sql语句:
SELECT 1 AS [C1], [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent2].[AppleId] AS [AppleId] FROM [dbo].[apple] AS [Extent1] LEFT OUTER JOIN [dbo].[banana] AS [Extent2] ON [Extent1].[Id] = [Extent2].[AppleId]
这样查询的结果的集合数据就和笛卡尔积后的临时表的行数是对应的了。在一对多的的情况下主表的数据会被重复哦。
右连接只要把 apple 和banana的顺序对调下就是了哦。
总结一下吧EF生成的sql语句是很灵活的,select的内容对最后生成的inner join还是left join的影响是很大的。以上写法仅供参考,当然左连接、右连接还有其他的写法。
-
全连接
那全连接怎么写呢,有点意外,其实很简单。
linq语法如下:
var res = from a in sys.Apple from b in sys.Banana select new { a.Id, a.Name, //Bananas = b1 t = b.AppleId };
生成的sql语句:
SELECT 1 AS [C1], [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent2].[AppleId] AS [AppleId] FROM [dbo].[apple] AS [Extent1] CROSS JOIN [dbo].[banana] AS [Extent2]
到这里就把连接查询介绍完了。在对多表进行查询的时候,连接查询应用的地方是很多的。提醒大家在查询多个表的时候,切忌使用foreach 或是 select里面写子查询,尽量用连接查询来替代。从我的实践来看大多数情况下连接查询的效率要比循环子查询高得多。甚至是10倍以上的差距。