2012-05-29 172 views
1

我想知道是否有更好的方法来构造我的linq查询(我使用EF CodeFirst)来访问我的表。眼下,它产生以下查询:实体框架和linq查询构建

exec sp_executesql N'SELECT 
[Project4].[Id] AS [Id], 
[Project4].[First] AS [First], 
[Project4].[Last] AS [Last], 
[Project4].[Email] AS [Email] 
FROM (SELECT 
    [Project3].[Id] AS [Id], 
    [Project3].[First] AS [First], 
    [Project3].[Last] AS [Last], 
    [Project3].[Email] AS [Email], 
    CASE WHEN ([Extent5].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] 
    FROM (SELECT 
     [Project2].[Id] AS [Id], 
     [Project2].[First] AS [First], 
     [Project2].[Last] AS [Last], 
     [Project2].[Email] AS [Email] 
     (SELECT 
      SUM([Extent4].[Data]) AS [A1] 
      FROM [dbo].[EventHistory] AS [Extent4] 
      WHERE [Project2].[Id] = [Extent4].[UserId]) AS [C1] 
     FROM (SELECT 
      [Extent1].[Id] AS [Id], 
      [Extent1].[First] AS [First], 
      [Extent1].[Last] AS [Last], 
      [Extent1].[Email] AS [Email] 
      (SELECT 
       SUM([Extent3].[Data]) AS [A1] 
       FROM [dbo].[EventHistory] AS [Extent3] 
       WHERE [Extent1].[Id] = [Extent3].[UserId]) AS [C1] 
      FROM [dbo].[User] AS [Extent1] 
      WHERE (EXISTS (SELECT 
       1 AS [C1] 
       FROM [dbo].[EventHistory] AS [Extent2] 
       WHERE [Extent1].[Id] = [Extent2].[UserId] 
      )) AND ([Extent1].[Id] = @p__linq__0) 
     ) AS [Project2] 
     WHERE [Project2].[C1] >= @p__linq__1) AS [Project3] 
    LEFT OUTER JOIN [dbo].[EventHistory] AS [Extent5] ON [Project3].[Id] = [Extent5]. [UserId] 
    WHERE [Project3].[C1] <= @p__linq__2 
) AS [Project4] 
ORDER BY [Project4].[Id] ASC, [Project4].[C1] ASC',N'@p__linq__0 int,@p__linq__1 int,@p__linq__2 int',@p__linq__0=1717,@p__linq__1=300,@p__linq__2=400 

...这似乎是相当可怕的我,为什么它会创建所有这些不同的子选择? - 对我来说,它真的应该产生类似于:

选择u.id,第一个,最后一个,电子邮件,e。*从用户u 左加入eventhistory e上e.userid = u.id和e.data < = @参数1和e.data> = @参数2 和u.id = @id

我的代码看起来是这样的:

IQueryable<User> query = from users in this.DataContext.Users.Include("EventHistoryList") 
           where users.EventHistoryList.Any() 
           select users; 

     if (playerId.HasValue) 
      query = query.Where(u => u.Id == playerId.Value); 

     if (dataLow.HasValue) 
      query = query.Where(u => u.EventHistoryList.Sum(p => p.Data) >= dataLow.Value); 

     if (dataHigh.HasValue) 
      query = query.Where(u => u.EventHistoryList.Sum(p => p.Data) <= dataHigh.Value); 

query = query.OrderByDescending(orderBy).Skip(startEntity).Take(pageSize).ToList(); 

任何帮助,将不胜感激。谢谢!

+0

对用户来说'EventHistoryList'是一个'ICollection'吗?这里有几个子选择。 – mattytommo

+0

这是...你会知道更好的方式来构建这个动态查询吗?我认为我在这里所做的是我真正做到这一点的唯一方法,不用自己编写t-sql并使用ado.net来获取它。 – user1368182

回答

1

它看起来像一个子选择处理分页,其他的是必要的,因为你正在对具有0 .. *关系的表应用聚合函数。我确信查询可以看起来更好,但我不认为这是不必要的低效率。

您认为应该生成的查询将从数据库中抓取整个结果集,并且还需要使用子查询来应用聚合函数。从数据库获取整个结果集并在之后进行分页将是非常低效的。

+0

我也总是看到它做了一个子选择,当它从一个表中选择id时 - 是否也应该这样做? – user1368182

+0

您是否将查询计划与您期望的内容进行了比较? EF不应该生成非常人性化的可读查询,它已经过优化以快速生成快速查询。另外,您可能想要EF5(可用于VS11beta),它在查询处理方面已经有了很大的改进,所以它可能会产生更好的效果。仍然没有必要生成易于阅读的东西:) – jessehouwing

+0

我实际上并没有比较这两个 - ef只是看起来很难读,但是再一次,有很多非常优化的代码也是不可读的。感谢您的建议! – user1368182