Поддерживает ли LINQ-to-SQL составные запросы?

Говоря как программист, не разбирающийся в C#, мне любопытна семантика оценки запросов LINQ, таких как следующие:

var people = from p in Person
             where p.age < 18
             select p

var otherPeople = from p in people
                  where p.firstName equals "Daniel"
                  select p

Предполагая, что Person является сущностью ADO, которая определяет поля age и firstName, что это будет делать с точки зрения базы данных? В частности, будет ли выполняться запрос people для создания структуры в памяти, которая затем будет запрашиваться запросом otherPeople? Или конструкция otherPeople просто извлечет данные о запросе из people, а затем создаст новый запрос к базе данных? Итак, если бы я повторил оба этих запроса, сколько операторов SQL было бы выполнено?


person Daniel Spiewak    schedule 18.09.2008    source источник


Ответы (5)


Они составные. Это возможно, потому что запросы LINQ на самом деле являются выражениями (код как данные), которые поставщики LINQ, такие как LINQ-to-SQL, могут оценивать и генерировать соответствующий SQL.

Поскольку запросы LINQ оцениваются лениво (например, не будут выполняться до тех пор, пока вы не выполните итерацию по элементам), код, который вы показали, на самом деле не будет касаться базы данных. Только после того, как вы выполните итерацию по другим людям или людям, SQL не будет сгенерирован и выполнен.

person Judah Gabriel Himango    schedule 18.09.2008

var people = from p in Person
             where p.age < 18
             select p

Переводит на:

SELECT [t0].[PersonId], [t0].[Age], [t0].[FirstName]
FROM [dbo].[Person] AS [t0]
WHERE [t0].[Age] < @p0

где @p0 передается как 18

var otherPeople = from p in people
                  where p.firstName equals "Daniel"
                  select p

Переводит на:

SELECT [t0].[PersonId], [t0].[Age], [t0].[FirstName]
FROM [dbo].[Person] AS [t0]
WHERE [t0].[FirstName] = @p0

где @p0 передается как «Дэниел»

var morePeople = from p1 in people
                 from p2 in otherPeople
                 where p1.PersonId == p2.PersonId
                 select p1;

Переводит на:

SELECT [t0].[PersonId], [t0].[Age], [t0].[FirstName]
FROM [dbo].[Person] AS [t0], [dbo].[Person] AS [t1]
WHERE ([t0].[PersonId] = [t1].[PersonId]) AND ([t0].[Age] < @p0) AND ([t1].[FirstName] = @p1)

где @p0 — 18, @p1 — «Даниил».

Если вы сомневаетесь, вызовите ToString() в IQueryable или передайте TextWriter свойству Log DataContext.

person Ant    schedule 18.09.2008

Да, результирующий запрос составлен. Он включает полное предложение where. Включите профилирование SQL и попробуйте сами.

Linq делает это с помощью деревьев выражений. Первый оператор linq создает дерево выражений; он не выполняет запрос. Второй оператор linq строится на дереве выражений, созданном первым. Оператор выполняется только при перечислении результирующей коллекции.

person Michael L Perry    schedule 18.09.2008

people и otherPeople содержат объекты типа IQueryable<Person>.

Если вы выполняете итерацию по обоим, отдельно, он будет выполнять два запроса. Если вы перебираете только otherPeople, он запустит ожидаемый запрос с двумя предложениями where.

Если вы выполняете .ToList() для people и используете возвращенный List<Person> во втором запросе вместо людей, он становится LINQ-to-Objects и SQL не выполняется.

Такое поведение называется отложенным выполнением. Это означает, что запрос не выполняется до тех пор, пока он не понадобится. Перед выполнением они представляют собой просто деревья выражений, которыми манипулируют, чтобы сформулировать окончательный запрос.

person David Thibault    schedule 18.09.2008

Оба эти запроса будут выполнены, когда вы попытаетесь получить доступ к окончательным результатам. Вы можете попробовать просмотреть исходный SQL, сгенерированный из свойств объекта DataContext.

person dimarzionist    schedule 18.09.2008