Являются ли запросы Linq to SQL и Linq to Objects одинаковыми? - PullRequest
6 голосов
/ 27 июня 2009

Если мы абстрагируем DataContext, то идентичны ли запросы L2S и L2O?

У меня уже есть работающий прототип, который демонстрирует это, но он очень прост, и мне интересно, выдержит ли он более сложные запросы.

Кто-нибудь знает?

Ответы [ 3 ]

9 голосов
/ 27 июня 2009

Нет, они не одинаковы.

Запросы LINQ to Objects работают с коллекциями IEnumerable<T>. Запрос выполняет итерацию по коллекции и выполняет последовательность методов (например, Contains, Where и т. Д.) Для элементов в коллекции.

LINQ to SQL-запросы работают с коллекциями IQueryable<T>. Запрос преобразуется компилятором в дерево выражений, и это дерево выражений затем переводится в SQL и передается в базу данных.

Обычно LINQ to SQL жалуется на то, что метод не может быть переведен в SQL, даже если этот метод отлично работает в запросе LINQ to Objects. (В других случаях вы можете не видеть исключение, но результаты запроса могут слегка отличаться между LINQ to Objects и LINQ to SQL.)

Например, LINQ to SQL захлебнется этим простым запросом, тогда как LINQ to Object будет в порядке:

var query = from n in names
            orderby n.LastName.TrimStart(',', ' ').ToUpper(),
                    n.FirstName.TrimStart(',', ' ').ToUpper()
            select new { n.FirstName, n.LastName };

(Часто можно обойти эти ограничения, но тот факт, что вы не можете гарантировать, что любой произвольный запрос LINQ to Objects будет работать как запрос LINQ to SQL, говорит мне, что они не совпадают!)

6 голосов
/ 27 июня 2009

К сожалению, все реализации IQueryably<T>, по сути, представляют собой утечку абстракций - и небезопасно предполагать, что что-то, что работает в LINQ-to-Objects, все же будет работать под любым другим поставщиком. Помимо очевидных отображений функций, такие вещи, как:

  • LINQ-to-SQL не может поддерживать все функции / перегрузки - перечислены здесь Типы данных и функции (LINQ to SQL)
  • плюс это зависит от фактического сервера базы данных; Пропустить / взять и т. Д. На SQL Server 2000 работают иначе, чем на 2005+, и не каждый такой перевод работает на SQL Server 2000
  • EF не поддерживает Single или Expression.Invoke (вызов подвыражения) или использование UDF
  • Astoria поддерживает различное использование Single / First; насколько я помню, он поддерживает Where(pred).Single() - но не Single(pred) (что является предпочтительным использованием для LINQ-to-SQL )

Таким образом, вы не можете реально использовать IEnumerable<T> для своих модульных тестов, имитирующих базу данных, даже через AsQueryable() - это просто не надежно. Лично я держу IQueryable<T> и Expression подальше от интерфейса репозитория по этой причине - см. Pragmatic LINQ .

5 голосов
/ 27 июня 2009

Синтаксис запроса такой же. Если вы используете Enumerable.ToQuerable, даже типы совпадают. Но есть некоторые отличия:

  • некоторые запросы будут работать только на L2O и приведут к ошибке времени выполнения в L2S (например, если дерево выражений содержит функцию, которая не может быть преобразована в SQL. Это не может быть обнаружено во время компиляции)
  • некоторые запросы возвращают разные результаты для L2S и L2O (пример: Макс ([пустая последовательность]) будет выдавать исключение в L2O, но возвращать ноль в L2S)

Итак, в конце концов, вам придется проверять базу данных, но я думаю, что L2O довольно хорош для простых и быстрых юнит-тестов.

...