Question

I have this query. fromdate and until are parameters.

List<TimeEntryReportModel> result = (
           from u in ctx.TT_Users
           join pm in ctx.TT_ProjectMembers on u.UserID equals pm.UserID
           join e in ctx.TT_EntryLogs on pm.UserID equals e.UserID
           join p in ctx.TT_Projects on e.ProjectID equals p.ProjectID
           where e.EntryDate >= fromdate && e.EntryDate <= until.Value && pm.TT_EntryLogs.Sum(q => q.Duration) > 0
           select new TimeEntryReportModel
           {
               UserId = e.UserID,
               DisplayName = u.DisplayName,
               UnitId = u.TT_BusinessUnits.UnitId,
               //select many more property's here that I get from e, p, pm, u etc.
           }
    ).Distinct().OrderBy(n => n.DisplayName).ToList();

In 3 of my controller methods I want to access SOME of the objects from this result. For example: In one method I want to have all of the TimeEntryReportModel objects where the user id's are a certain value.

So the method looks like this (where userId is a parameter in the method):

 return result.Where(e => e.UserId == userId).ToList();

Another method looks like this:

return result.Where(l => l.UnitId == unitId).ToList();

This pretty much works, but because the result contains about 420 TimeEntryReportModels, and inside the other methods I have to take a sub query of that result, it takes about 10 seconds before I actually receive the data I need.

One way to solve this is to copy and paste the query 3 times and add the necessary where condition right into each query. But this seems devious, because I'm basically just rewriting this whole query just for one single condition... Can't I add a condition to the query based on a parameter that I pass to the method that contains this query?

tl;dr Is it possible to add a condition to a LINQ query based on a parameter?

Was it helpful?

Solution

The use of the .ToList() function in the construction of the variable result, leads to execute the query. Considering result as a variable of type IQueryable<TimeEntryReportModel> instead of a list, the request will be executed later (when calling .ToList() in the controller method). So, you can write:

IQueryable<TimeEntryReportModel> result = (
...
).Distinct().OrderBy(n => n.DisplayName);

And later (in same or other function), specify the query by adding the where clause:

...
var specifiedResult = result.Where(e => e.UserId == userId).ToList();

Deferred execution is, in my opinion, one of the main interests of LINQ.

OTHER TIPS

Sort of, you can use a logical OR to get the same effect. For example, let's say that I had a date parameter and the date was optional, and the query always check for an id. You can structure your Where call like this:

from u in ctx.TT_Users 
where u.userId >= 1001
    && (myDateParam == null || u.RegisteredOn >= myDateParam);

If myDateParam is specified, then the where returns all users with ids greater than 1001 who registered after the specified date. Obviously, my example is fictitious...the principle might help you. If myDateParam is not specified, then all users with ids greater than 1001 are returned.

Short-circuiting, of course, is what makes this possible. You can also do this with booleans and lists, etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top