如何使用查询语法在 linq to entities 查询中使用此扩展方法?

How can I use this extension method in a linq to entities query using query syntax?

我正在为 return 数据库中的一些数据创建查询。 我正在传递要过滤的 ID 列表。如果过滤器列表为 null 或空,我想 return 所有的东西。

我有一个扩展方法可以让我这样做 query 是一个 IQueryableIds 是一个可空整数列表(不要问!)ListHasElements 是一个方法,如果列表 return 为真是非空的,里面有东西。

 var filteredList = query.WhereIf(ListHasElements(Ids), s => Ids.Contains(s.Id.Value));

然而,当我构建 query 时,我使用我喜欢的查询语法

var query = from a in dbContext.as
            join b in dbContext.bs on a.Id.ToString() equals b.Id
            join cin dbContext.cs on b.Id equals c.Id into bcJoin
            from items in bcJoin.DefaultIfEmpty()
            where b.Sent >= fromDate
            where b.Sent <= toDate
            select new{a=a.thing, b=b.thingy, q=items.q,Id=a.Id}

然后我必须插入初始行来执行我神奇的 WhereIf 过滤器。最后 select 分组并创建我的输出对象(代码未显示!)

扩展方法如下所示。

public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition,
    Expression<Func<TSource, bool>> predicate)
{
    return condition ? source.Where(predicate) : source;
}

我可以直接在我的查询语法查询中使用这个方法吗?

引自MSDN

Some queries must be expressed as method calls

这是其中一个案例。甚至他们自己的一些扩展方法也必须通过方法语法来调用。例如,Count.

你不能。编译器采用众所周知的查询语法关键字并将它们转换为幕后方法语法。它对您的自定义扩展一无所知,因此在查询语法中没有等效项。请注意,其他 "built-in" linq 函数没有等效的查询语法:

  • Skip
  • Count
  • Take
  • Single
  • FirstOrDefault
  • Max
  • 等等

尽管我会注意到您的扩展基本上等同于

where !condition || predicate(b)

是的!

var query = from a in dbContext.as.WhereIf(ListHasElements(Ids), s => Ids.Contains(s.Id.Value))
        join b in dbContext.bs on a.Id.ToString() equals b.Id
        join cin dbContext.cs on b.Id equals c.Id into bcJoin
        from items in bcJoin.DefaultIfEmpty()
        where b.Sent >= fromDate
        where b.Sent <= toDate
        select new{a=a.thing, b=b.thingy, q=items.q,Id=a.Id}

我的测试代码(列表是一个带有 Id 字段的 table):

void Main()
{
   var list=new int []{1,2,3,4};
   var query=from l in Listings.WhereIf(ListHasElements(list),s=>list.Contains(s.Id))
   select l;
   query.Dump();
}
public bool ListHasElements<T>(IEnumerable<T> it)
{
    return it.Any();
}

public static class Ext {
    public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition,
        Expression<Func<TSource, bool>> predicate)
    {
        return condition ? source.Where(predicate) : source;
    }
}