Как повторно использовать оператор where в запросах Linq To Sql - PullRequest
14 голосов
/ 10 февраля 2011

У меня есть пользователи, которые ищут записи типа Record.Они вводят поисковый термин в текстовое поле, а затем я ищу записи, сопоставляя несколько полей с поисковым термином.

Мой запрос выглядит так:

var results = from record in DataContext.Records
              where
                   record.Field1.ToLower().Contains(term) ||
                   record.Field2.ToLower().Contains(term) ||
                   record.Field3.ToLower().Contains(term)
              select record;

У меня есть несколько запросов, которые всеиспользуйте тот же фильтр, и поэтому я хотел бы извлечь фильтр, чтобы его можно было использовать повторно.Что-то вроде:

var filter = new Func<Record, string, bool>(
                (record, term) =>
                    record.Field1.ToLower().Contains(term) ||
                    record.Field2.ToLower().Contains(term) ||
                    record.Field3.ToLower().Contains(term)
             );

var results = from record in DataContext.Records
              where filter(record, term)
              select record;

Однако это не работает, потому что:

Метод 'System.Object DynamicInvoke (System.Object [])' не поддерживает перевод на SQL.

Как я могу использовать мое условие where в запросах?

Ответы [ 4 ]

13 голосов
/ 10 февраля 2011

Вам нужно построить выражение вместо функции:

Expression<Func<Record, bool>> filter = 
  record => record.Field1.ToLower().Contains(term);  // rest omitted

Лямбда-выражение остается прежним, но вам нужно вернуть его в переменную типа Expression<Func<Record, bool>> - которая сделаетКомпилятор C # компилирует его как выражение, а не делегат, что позволяет передавать его в LINQ to SQL.

Однако вы не сможете использовать переменную выражения с C # -синтаксисом условия where: youВам нужно будет использовать метод расширения Where:

var results = DataContext.Records.Where(filter);

Отредактировано, чтобы добавить: Если вы хотите иметь возможность создавать фильтры на разных условиях, вам просто нужен метод для созданиявыражение из термина:

private static Expression<Func<Record, bool>> Filter(string term)
{
  return r => r.Field1.ToLower().Contains(term);
}

var results = DataContext.Records.Where(Filter(term));

Если вы предпочитаете сохранять filter лямбда-выражением, как в данный момент, вы можете сделать это, но обобщенные элементы немного вложены:

Func<string, Expression<Func<Record, bool>>> filter =
  term => (r => r.Field1.ToLower().Contains(term));

var results = DataContext.Records.Where(filter(term));

Несмотря на это, важно то, что в предложении Where должно быть указано Expression<Func<Record, bool>>, но, как показано выше, вы можете сделать выражение зависимым от term, построив подходящее выражение на лету.Именно это будет делать LINQ to SQL, если вы укажете от руки фильтр в предложении Where.

13 голосов
/ 10 февраля 2011

Используйте CompiledQuery !

var filter = CompiledQuery.Compile(
    (DatabaseDataContext dc, Record record, string term) =>
        record.Field1.ToLower().Contains(term) ||
        record.Field2.ToLower().Contains(term) ||
        record.Field3.ToLower().Contains(term)
);

var results = from record in DataContext.Records
              where filter(DataContext, record, term)
              select record;

Для получения дополнительной информации см. Как: хранить и повторно использовать запросы .

3 голосов
/ 10 февраля 2011

В дополнение к проблеме Expression<Func<Record, bool>>, на которую указывали другие, я предлагаю изучить PredicateBuilder . Это очень хорошо для динамического объединения лямбда-выражений.

1 голос
/ 10 февраля 2011

Я думаю, вам нужно сделать это Expression<Func<Record, bool>>. В противном случае он пытается перевести фактический вызов метода C # в SQL, а не его описание. Это не гарантия того, что эта версия будет работать; Я не уверен, какие строковые функции могут быть переведены в SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...