user1368182
user1368182

Reputation: 473

Entity framework and linq query construction

I'm wondering if there is a better way to construct my linq query (I am using EF CodeFirst) to access my tables. Right now, it produces the following query:

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

...and this seems pretty horrendous to me, and why does it create all these different sub selects? - to me, it really should be producing something like:

select u.id, first, last, email, e.*
from user u 
left join eventhistory e
    on e.userid = u.id
   and e.data <= @param1
   and e.data >= @param2
   and u.id = @id

My code looks something like this:

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();

Any help would be appreciated. Thanks!

Upvotes: 1

Views: 303

Answers (1)

w.brian
w.brian

Reputation: 17367

It looks like one of the sub selects handles the paging, and the others are necessary because you're applying an aggregate function against a table that has a 0..* relationship. I'm sure the query could be made to look nicer, but I don't think it is needlessly inefficient.

The query you think it should be producing would grab the entire result set from the database and would also require a subselect to apply the aggregate function. It would be pretty inefficient to get the entire result set from the database and do the paging afterward.

Upvotes: 1

Related Questions