我对使用 EF 5 进行查询的“最佳实践”方式很感兴趣。
例如,让我们有 2 个表:Movie 和 Genre,它们具有多对多关系,因此有第三个表 GenreMovie,其中 MovieId 和 GenreId 作为 FK。
这意味着一种类型有几部电影,但一部电影也可以是多种类型的混合。
在客户端有 2 个网格,左侧为流派列表,右侧为电影列表。
对于选定的流派,电影列表不仅会显示该流派的电影,还会显示所有电影,其中将检查属于该流派的电影。
此选择可以通过两种方式完成,具有相同的结果。
int 流派 ID = 1; (选择了 id = 1 的流派)
使用 EF 关联
var q = db.Movies .Select(m => new { MovieId = m.MovieId, Title = m.Title, Selected = m.GenreMovies.Where(gm => gm.GenreId == genreId).Count() > 0, });
使用 Linq 连接
var q = from m in db.Movies join gm in db.GenreMovies.Where(gm => gm.GenreId == genreId) on m.MovieId equals gm.MovieId into gms from gm in gms.DefaultIfEmpty() select new { MovieId = m.MovieId, Title = m.Title, Selected = gm != null };
显然,第一种方式代码更少,看起来更简单。
但这真的是更好的方法和最佳实践吗?
因为我听说 EF 关联并不总是能最好地转换为关于优化的 SQL 查询。
我还查看了 Sql Profiler 以查看两种方式的结果查询。我看到了以下内容:(1.方式似乎用更多行进行查询,但我不确定它是否效率较低)???
我试图用数十万条记录进行一些测试,但两种方式都太快了,看不出有什么区别。
1.
exec sp_executesql N'SELECT
[Project2].[MovieId] AS [MovieId],
[Project2].[Title] AS [Title],
CASE WHEN ([Project2].[C1] > 0) THEN cast(1 as bit) WHEN ( NOT ([Project2].[C2] > 0)) THEN cast(0 as bit) END AS [C1]
FROM ( SELECT
[Project1].[MovieId] AS [MovieId],
[Project1].[Title] AS [Title],
[Project1].[C1] AS [C1],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[GenreMovie] AS [Extent3]
WHERE ([Project1].[MovieId] = [Extent3].[MovieId]) AND ([Extent3].[GenreId] = @p__linq__0)) AS [C2]
FROM ( SELECT TOP (1000)
[c].[MovieId] AS [MovieId],
[c].[Title] AS [Title],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[GenreMovie] AS [Extent2]
WHERE ([c].[MovieId] = [Extent2].[MovieId]) AND ([Extent2].[GenreId] = @p__linq__0)) AS [C1]
FROM [dbo].[Movie] AS [c]
) AS [Project1])
AS [Project2]',N'@p__linq__0 int',@p__linq__0=1
2.
exec sp_executesql N'SELECT
[Limit1].[MovieId] AS [MovieId],
[Limit1].[Title] AS [Title],
CASE WHEN ([Limit1].[GenreMovieId] IS NOT NULL) THEN cast(1 as bit) WHEN ([Limit1].[GenreMovieId] IS NULL) THEN cast(0 as bit) END AS [C1]
FROM ( SELECT TOP (1000)
[Extent1].[MovieId] AS [MovieId],
[Extent1].[Title] AS [Title],
[Extent2].[GenreMovieId] AS [GenreMovieId]
FROM [dbo].[Movie] AS [Extent1]
LEFT OUTER JOIN [dbo].[GenreMovie] AS [Extent2] ON ([Extent2].[GenreId] = @p__linq__0) AND ([Extent1].[MovieId] = [Extent2].[MovieId]))
AS [Limit1]',N'@p__linq__0 int',@p__linq__0=1