views:

104

answers:

3

I have a form that allows the user to perform a myriad of searches. The table(s) that need to be joined differ depending on the search criteria entered. (My example below is very simplistic because both tables use the same sub-tables to join on, but the actual problem is not as simple.)

I've been using a technique I call LINQ stacking, like this:

IQueryable<LogENT> results = Context.AssignedLogsENT.Where(l => l.AgencyId);

if(txtFirstName.Text != null)
    results = from r in results
         join a in Context.LogAssignmentsENT on r.DisplayLogId equals a.LogId
         join p in Context.PersonsENT on a.ObjectId equals p.DisplayPersonId
         && !a.Deleted &&
         p.FirstName.StartsWith(Object.FirstName)
         select r;

if(txtLastName.Text != null)
    results = from r in results
         join a in Context.LogAssignmentsENT on r.DisplayLogId equals a.LogId
         join p in Context.PersonsENT on a.ObjectId equals p.DisplayPersonId
         && !a.Deleted &&
         p.LastName.StartsWith(Object.LastName)
         select r;

So you see if a certain text field is set, I add to the query as necessary. This actually works fine, except that when I use SQL Profiler to view the generated query, it is INNER JOINing the tables each time I add a new criterion.

i.e. the LogAssignments table is included 3, 4, 5 times. Is there a way I can prevent it from JOINing the same table more than once?

Or, is there a better way I can do this? I've looked at Predicate Builder however it doesn't seem to permit joining tables, which is a requirement in my case.

Thanks!

A: 

You can build your base result and then dynamically add the where clauses.

Patrick
But the problem is the wheres depend on the joined tables, and so I can't reference the joined tables in the dynamically added wheres...
msigman
+1  A: 

If you use just one query, you could modify it something like this:

results = from r in results 
         join a in Context.LogAssignmentsENT on r.DisplayLogId equals a.LogId 
         join p in Context.PersonsENT on a.ObjectId equals p.DisplayPersonId 
         && !a.Deleted && 
         (txtFirstName.Text != null || p.FirstName.StartsWith(Object.FirstName)) &&
         (txtLastName.Text != null || p.LastName.StartsWith(Object.LastName))
         select r; 
John Fisher
Thanks but I need a way to make the "joins" optional as well...
msigman
@user482286: Have you checked the resulting query to see that there actually are joins because of this?
John Fisher
+2  A: 
IQueryable<LogENT> results = Context.AssignedLogsENT.Where(l => l.AgencyId);


results = from r in results
    join a in Context.LogAssignmentsENT on r.DisplayLogId equals a.LogId
    join p in Context.PersonsENT on a.ObjectId equals p.DisplayPersonId
    && !a.Deleted
    select r;

if(txtFirstName.Text != null)
    results = from r in results
         p.FirstName.StartsWith(Object.LastName)
         select r;

if(txtLastName.Text != null)
    results = from r in results
         p.LastName.StartsWith(Object.LastName)
         select r;
Andrew Lewis
This approach doesn't work because "p" is not defined in any of the subsequent queries.
msigman