使用EF 5查询,关联VS Linq加入

时间:2013-04-24 22:42:10

标签: linq entity-framework join ef-code-first associations

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

例如,让我们有2个表:电影和流派有多对多的关系,所以有第三个表GenreMovie,其中MovieId和GenreId为FK。

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

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

对于选定的类型,电影列表不仅会显示该类型的电影,还会显示所有属于此类型的电影。

此选择可以在2路上完成,具有相同的结果。

int genreId = 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 join

    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
             };
    
  3. 显然,第一种方法代码更少,看起来更简单。

    但它是真的更好的方式,也是最好的做法?

    因为我听说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
    

1 个答案:

答案 0 :(得分:0)

我会这样写:

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

仅出于简单原因。