Как применить динамические фильтры для Linq-To-Entites и выполнить их на стороне сервера - PullRequest
3 голосов
/ 15 ноября 2011

Я хочу написать класс, который предоставляет в основном список записей. Эти записи могут быть либо прочитаны из базы данных, либо сгенерированы во время жизни приложения. Этот класс должен обеспечивать способ фильтрации этих записей. Можно ли реализовать фильтры таким образом, чтобы для обоих источников требовался только один фильтр?

Например:

interface IFilter
{
    bool Filter(ILogEntry entry);
}

Для LINQ с IEnumerable нет проблем с применением его в качестве динамических фильтров.

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. Как я могу гарантировать, что запрос будет выполняться на сервере, а не локально?

Мне кажется немного странным, что следующий код фактически выполняет фильтр на сервере. Но если я использую IFilter в этом запросе, который принимает ILogEntry (который реализуется LogEntry) в качестве аргумента, фильтр будет применен на стороне клиента:

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

Есть ли способ написать фильтры для ICollection и IQueryable и обеспечить выполнение фильтров для IQueryable на SQL-сервере?

1 Ответ

3 голосов
/ 15 ноября 2011

Единственный способ применить эту сторону сервера, составив ее как деревья выражений , например:

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

Примечание: если у вас в памяти имеется порция данных, вы можете переключиться с IEnumerable<T> на IQueryable<T>, используя .AsQueryable(), что позволяет локально использовать дерево выражений.

...