Проверьте выражение LINQ to SQL - PullRequest
2 голосов
/ 27 июля 2011

Я пишу приложение, которое работает с базой данных MS SQL через LINQ to SQL.Иногда мне нужно выполнять фильтрацию, а иногда мои условия фильтрации слишком сложны, чтобы их можно было перевести в SQL-запрос.Хотя я пытаюсь сделать их переводимыми, я хочу, чтобы мое приложение по крайней мере работало, хотя иногда и медленно.

Модель данных LINQ to SQL скрыта внутри репозиториев, и я не хочу предоставлять несколько перегрузок метода GetAll дляразные случаи и помните, какую перегрузку использовать на верхних уровнях.Поэтому я хочу проверить свое выражение внутри репозитория на возможность перевода и, если нет, выполнить запрос в памяти для всего набора данных вместо того, чтобы выдавать исключение NotSupportedException при создании экземпляра запроса.

Это то, что у меня сейчас есть:

IQueryable<TEntity> table = GetTable<TEntity>();
IQueryable<TEntity> result;
try
{
    result = table.Where(searchExpression);

    //this will test our expression 
    //consuming as little resources as possible (???)        
    result.FirstOrDefault(); 
}
catch (NotSupportedException)
{
    //trying to perform in-memory search if query could not be constructed
    result = table
        .AsEnumerable()
        .Where(searchExpression.Compile())
        .AsQueryable();
}
return result;

searchExpression - это Expression<Func<TEntity, bool>>

Как видите, я использую FirstOrDefault, чтобы попытаться создать экземплярзапросить и выбросить исключение, если оно не может быть создано.Тем не менее, он будет выполнять бесполезный вызов базы данных, когда выражение хорошо.Я мог бы использовать Any, Count или другой метод, и он вполне может быть немного дешевле, чем FirstOrDefault, но все же все методы, которые мне приходят в голову, делают дорогостоящую поездку в базу данных, в то время как все, что мне нужно, этопроверить мое выражение.

Есть ли альтернативный способ сказать, является ли мое выражение «хорошим» или «плохим», без фактического вызова базы данных?

ОБНОВЛЕНИЕ:

Или, в более общем смысле, есть ли способ сообщить LINQ делать запросы в памяти, когда он не может создать SQL, так что этот механизм тестирования вообще не понадобится?

Ответы [ 2 ]

2 голосов
/ 27 июля 2011

вместо

   result.FirstOrDefault(); 

будет достаточно использовать

    string sqlCommand = dataContext.GetCommand(result).CommandText; 

Если выражение не генерирует действительный Sql, это должно вызвать исключение NotSupportedException, но оно фактически не выполняет sqlCommand.

1 голос
/ 27 июля 2011

Я думаю, что это решит вашу проблему:

IQueryable<TEntity> table = GetTable<TEntity>();  
IQueryable<TEntity> result;
try
{
    return table.Where(searchExpression).ToList();
}
catch (NotSupportedException)
{
    //trying to perform in-memory search if query could not be constructed
    return table
        .AsEnumerable()
        .Where(searchExpression.Compile())
        .ToList();
}

Таким образом, метод возвращает выражение, преобразованное в допустимый SQL. В противном случае он перехватывает исключение и запускает запрос в памяти. Это должно работать, но не отвечает на ваш вопрос, если можно проверить, можно ли преобразовать конкретный searchExpression. Я не думаю, что такая вещь существует.

...