如何为链接到实体应用动态过滤器并在服务器端执行它们

本文关键字:服务器端 执行 过滤器 动态 链接 应用 实体 | 更新日期: 2023-09-27 18:14:45

我想写一个类,它基本上提供了一个条目列表。这些条目既可以从数据库中读取,也可以在应用程序生存期内生成。该类应该提供一种过滤这些条目的方法。是否有可能实现两个源只需要一个过滤器的过滤器?

例如:

interface IFilter
{
    bool Filter(ILogEntry entry);
}

对于带有IEnumerable的LINQ,将其应用为动态过滤器没有问题。

IEnumerable<IFilter> filters;
IEnumerable<ILogEntry> entries;
foreach(var filter in filters)
    entries = entries.Where(p => filter.Filter(p));

但是对于Linq-To-Sql,有两个问题我没有解决方案:

  1. 如何将上下文提供的LogEntry转换为ILogEntry?
  2. 我如何确保查询将在服务器上执行而不是在本地执行?

下面的代码将在服务器上实际执行过滤器,这对我来说似乎有点奇怪。但是,如果我在这个以ILogEntry(由LogEntry实现)作为参数的查询中使用filter,则过滤器将在客户端应用:

entities.Logs
    .Select(p => new LogEntry() { Message = p.Message })
    .Where(p => p.Message == "132");

是否有一种方法可以为iccollection和IQueryable编写过滤器,并确保IQueryable过滤器将在SQL-Server上执行?

如何为链接到实体应用动态过滤器并在服务器端执行它们

应用该服务器端的唯一方法是将组合为表达式树,例如:

interface IFilter {
    public Expression<Func<ILogEntry, bool>> GetPredicate();
}
...
IQueryable<ILogEntry> entries = ...
foreach(var filter in filters) {
    entries = entries.Where(filter.GetPredicate());
}

这就要求实现如下:

public Expression<Func<ILogEntry, bool>> GetPredicate() {
    return x => x.SomeField == 25;
}

注意:如果你有一个内存中的数据缺口,你可以通过使用.AsQueryable()IEnumerable<T>切换到IQueryable<T>,这允许它在本地使用表达式树