1

我对使用 EF 5 进行查询的“最佳实践”方式很感兴趣。

例如,让我们有 2 个表:Movie 和 Genre,它们具有多对多关系,因此有第三个表 GenreMovie,其中 MovieId 和 GenreId 作为 FK。

这意味着一种类型有几部电影,但一部电影也可以是多种类型的混合。

在客户端有 2 个网格,左侧为流派列表,右侧为电影列表。

对于选定的流派,电影列表不仅会显示该流派的电影,还会显示所有电影,其中将检查属于该流派的电影。

此选择可以通过两种方式完成,具有相同的结果。

int 流派 ID = 1; (选择了 id = 1 的流派)

  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,
          });
    
  2. 使用 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
4

1 回答 1

0

我会这样写:

var q = db.Movies
      .Select(m => new
      {
          MovieId = m.MovieId,
          Title = m.Title,
          Selected = m.GenreMovies.Any(gm => gm.GenreId == genreId),
      });

仅出于简单的原因。

于 2013-04-26T11:08:32.190 回答