tags:

views:

397

answers:

1

I have some predicates being dynamically built that have the following signature passes through as parameters into a function:

Expression<Func<TblTableR, bool>> TableRPredicate,
Expression<Func<TblTableN, bool>> suspectNamesPredicate,
Expression<Func<TblTableS, bool>> TableSPredicate,
Expression<Func<TblTableI, bool>> suspectTableIPredicate,

I am trying to query using the following:

var registries = (from r in db.TblTableR.Where(TableRPredicate)
join s in db.TblTableS.Where(TableSPredicate) 
        on r.TblTableRID equals s.TblTableSTableRID into ss
from suspects in ss.DefaultIfEmpty()
    join si in db.TblTableI.Where(suspectTableIPredicate) 
        on suspects.TblTableSIndexCardID equals si.TblTableIID into sisi
    from suspectTableI in sisi.DefaultIfEmpty()
    join sn in db.TblTableN.Where(suspectNamesPredicate) 
        on suspectTableI.TblTableIID equals sn.TblTableNIndexCardID into snsn
    from suspectNames in snsn.DefaultIfEmpty()
    select r.TblTableRID).Distinct();

This has the result of putting any generated "where" clause into the JOIN statement eg:

left outer join tblTableI on tblTableITableRID = tblTableRID 
   AND (expression created by predicate)

What is actually happening is that the final SQL that is created is incorrect. It is creating the following type of sql

 select * from table1 left outer join table2 on field1 = field2 
    AND field3 = 'CRITERIA'

It is this AND clause on the end that is the problem - ending up returning too many rows. Essentially I would like to get the where clause into the statement and not have it stick the extra condition into the join.

Something like this:

select * from table1 left outer join table2 on field1 = field2 
    WHERE field3 = 'CRITERIA'

I have tried adding a Where clause in as follows:

...
...
...
select r.TblTableRID).Where(TableRPredicate).Distinct();

but that will not compile because of the generic parameters on each predicate.

If I modify my LINQ query to only select from one table and use a predicate, the WHERE clause is generated correctly.

Any ideas?

+1  A: 

(edited post clarification)

Step 1; change the final select to select all three entities into an anonymous type; for me (testing on Northwind), that is:

select new {emp, cust, order};

Step 2; apply your filters to this using the extension method I've added below; for me this filtering looks like:

var qry2 = qry.Where(x => x.emp, employeeFilter)
            .Where(x => x.cust, custFilter)
            .Where(x => x.order, orderFilter);

Step 3; now select the entity/entities you actually want from this filtered query:

var data = qry2.Select(x => x.order)

And here's the extension method:

static IQueryable<T> Where<T,TValue>(
    this IQueryable<T> source,
    Expression<Func<T, TValue>> selector,
    Expression<Func<TValue, bool>> predicate)
{
    var row = Expression.Parameter(typeof (T), "row");
    var member = Expression.Invoke(selector, row);
    var lambda = Expression.Lambda<Func<T, bool>>(
        Expression.Invoke(predicate, member), row);
    return source.Where(lambda);
}
Marc Gravell
Marc,I have updated the post to make things a bit clearer.Peter
Peter
OK; I hope this update fixes things for you.
Marc Gravell
Thanks Marc, that solved the problem!
Peter