如何为EntitySet构造Where子句

时间:2014-05-16 03:07:51

标签: c# linq linq-to-sql

假设我有两个表连接外键约束。请考虑以下代码:

using(var dc = TestDataContext())
{
    IQueryable<ParentTable> query = dc.ParentTable;  
    query = query.Where(t => t.ChildTable.Where(c => c.Name.StartsWith("#")).Any());
    Console.WriteLine(query.Count());
}

如果我需要在某些条件下扩展Where子句,我只需链接Where子句:

if(...)
    query = query.Where(...);
...

实际上它会通过sql中的Where语句添加到原始AND子句中。

现在想象一下,我需要在Where ChildTable子句中的ParentTable上动态构建Where子句...

我试着这样做:

using(var dc = TestDataContext())
{
    IQueryable<ParentTable> query = dc.ParentTable;  

    //here specify the necessary condition 
    Func<ChildTable, bool> where;
    if(...)
        where = c => c.Name.StartsWith("#");
    else ...

    query = query.Where(t => t.ChildTable.Any(where));
    Console.WriteLine(query.Count());
}

然而它会抛出NotSupportedException,说它无法正确地将where指定的Func Any转换为sql。

我认为我可以指定Expression<Func<ChildTable, bool>>,但t.ChildTableEntitySet<ChildTable>,因此它不会实现IQueryable<T> ...因此无法翻译自定义Func<>正确地进入sql。

有没有办法实现这个目标,除了每次只重写整个语句:

1. query = query.Where(t => t.ChildTable.Where(c => c.Name.StartsWith("#")).Any());

2. query = query.Where(t => t.ChildTable.Where(c => c.Name.StartsWith("#") && ...).Any()));

...

1 个答案:

答案 0 :(得分:0)

如果我需要动态where子句,我喜欢使用PredicateBuilder

将该网站上的示例翻译成您的问题会提供以下代码。如果您使用EF,则可能需要使用.AsExpandable()进行操作,请参阅该链接以获取更多信息。

var predicate = PredicateBuilder.False<ParentTable>();
predicate = predicate.Or(p => p.ChildTable.Any(c => c.Name.StartsWith("#"));

var keywords = "search terms go here";
foreach (var keyword in keywords)
{
  var temp = keyword;
  predicate = predicate.Or(p => p.ChildTable.Any(c => c.Name.Contains(temp));
}

using(var dc = TestDataContext())
{
  Console.WriteLine(dc.ParentTable.Where(predicate).Count());
}