使用LINQ和动态创建的谓词进行动态搜索

时间:2009-02-20 07:03:54

标签: linq-to-sql

我有一些动态构建的谓词,它们将以下签名作为参数传递给函数:

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

我正在尝试使用以下内容进行查询:

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

这具有将任何生成的“where”子句放入JOIN语句的结果,例如:

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

实际发生的是创建的最终SQL不正确。它正在创建以下类型的sql

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

最后这个AND子句是问题 - 最终返回太多行。基本上我想把where子句放到语句中,而不是让额外的条件加入到连接中。

这样的事情:

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

我尝试过添加Where子句,如下所示:

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

但由于每个谓词上的泛型参数,因此无法编译。

如果我将LINQ查询修改为仅从一个表中选择并使用谓词,则会正确生成WHERE子句。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

(编辑后澄清)

第1步;更改最终选择以将所有三个实体选择为匿名类型;对我来说(在Northwind上测试),即:

select new {emp, cust, order};

第2步;使用我在下面添加的扩展方法将您的过滤器应用于此;对我来说,这个过滤看起来像:

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

第3步;现在从过滤的查询中选择您真正想要的实体/实体:

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

这是扩展方法:

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