Преобразование стандартных операторов запросов (LINQ to SQL)

Обновлен: November 2007

Технология LINQ to SQL преобразует стандартные операторы запросов в команды SQL. Семантика выполнения преобразования SQL определяется обработчиком запросов базы данных.

Все стандартные операторы запросов определяются для последовательностей. Последовательность является упорядоченной и основывается на идентификации ссылки для каждого элемента последовательности. Дополнительные сведения см. в разделе Общие сведения о стандартных операторах запроса.

SQL работает, в первую очередь, с неупорядоченными наборами значений. Упорядочение, которое, как правило, задается явным образом, является операцией завершающей обработки, применяемой к окончательному результату запроса, а не к промежуточным результатам. Идентификация определяется значениями. По этой причине запросы SQL работают скорее с мультинаборами (контейнерами), чем с наборами.

Далее приводится описание различий между стандартными операторами запросов и их преобразованиями SQL для поставщика SQL Server для LINQ to SQL.

Поддержка операторов

Concat

Метод Concat<TSource> определен для упорядоченных мультинаборов, в которых порядок получателя и порядок атрибута совпадают. Метод Concat<TSource> работает как предложение UNION ALL над мультинаборами с общим порядком.

Завершающее действие состоит в упорядочении в SQL перед возвращением результатов. Метод Concat<TSource> не сохраняет порядок своих аргументов. Чтобы обеспечить соответствующее упорядочение, необходимо явно упорядочить результаты метода Concat<TSource>.

Intersect, Except, Union

Методы Intersect и Except правильно определяются только для наборов. Семантика для мультинаборов не определена.

Метод Union определен для мультинаборов как неупорядоченное объединение мультинаборов (в действительности, он возвращает результат, аналогичный предложению UNION ALL в SQL).

Take, Skip

Методы Take<TSource> и Skip<TSource> правильно определяются только для упорядоченных наборов. Семантика для неупорядоченных наборов или мультинаборов не определена.

Bb399342.alert_note(ru-ru,VS.90).gifПримечание.

Методы Take<TSource> и Skip<TSource> имеют некоторые ограничения, когда они применяются в запросах SQL Server 2000. Дополнительные сведения см. в подразделе "Исключения методов "Skip" и "Take" в SQL Server 2000" раздела Устранение неполадок (LINQ to SQL).

Из-за ограничений, накладываемых на упорядочение в SQL, технология LINQ to SQL пытается переместить упорядочение аргументов этих методов в результат метода. Рассмотрим, например, следующий запрос LINQ to SQL:

Dim custQuery = _
    From cust In db.Customers _
    Where cust.City = "London" _
    Order By cust.CustomerID _
    Select cust Skip 1 Take 1
var custQuery = 
    (from cust in db.Customers
    where cust.City == "London"
    orderby cust.CustomerID
    select cust).Skip(1).Take(1);

В созданных для этого кода командах SQL упорядочение перемещается в конец:

SELECT TOP 1 [t0].[CustomerID], [t0].[CompanyName],
FROM [Customers] AS [t0]
WHERE (NOT (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM (
        SELECT TOP 1 [t1].[CustomerID]
        FROM [Customers] AS [t1]
        WHERE [t1].[City] = @p0
        ORDER BY [t1].[CustomerID]
        ) AS [t2]
    WHERE [t0].[CustomerID] = [t2].[CustomerID]
    ))) AND ([t0].[City] = @p1)
ORDER BY [t0].[CustomerID]

Становится очевидным, что при объединении методов Take<TSource> и Skip<TSource> все указанные операции упорядочения должны быть согласованными. В противном случае результаты не определены.

Методы Take<TSource> и Skip<TSource> правильно определяются для неотрицательных постоянных интегральных аргументов, соответствующих спецификации стандартных операторов запросов.

Операторы без преобразования

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

Операторы

Обоснование

TakeWhile, SkipWhile

Запросы SQL работают с мультинаборами, а не последовательностями. Последним предложением, применяемым к результатам, должно быть предложение ORDER BY. По этой причине преобразование общего назначения для этих двух методов отсутствует.

Reverse<TSource>

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

Last, LastOrDefault

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

ElementAt<TSource>, ElementAtOrDefault<TSource>

Запросы SQL работают с мультинаборами и не работают с индексируемыми последовательностями.

DefaultIfEmpty (перегрузка с аргументом по умолчанию)

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

Преобразование выражений

Семантика значений NULL

Технология LINQ to SQL не накладывает семантику сравнения со значением NULL на команды SQL. Операторы сравнения синтаксически преобразуются в эквивалентные команды SQL. По этой причине семантика отражает семантику SQL в соответствии с параметрами сервера или подключения. Например, в соответствии с заданными по умолчанию параметрами SQL Server два значения NULL считаются неравными, хотя, чтобы изменить семантику, можно изменить эти параметры. При преобразовании запросов LINQ to SQL не принимает во внимание настройки сервера.

Сравнение с литералом NULL преобразуется в соответствующую версию SQL (is null или is not null).

Значение null в параметрах сортировки определяется приложением SQL Server. Технология LINQ to SQL не изменяет параметров сортировки.

Статистические выражения

Статистический метод Sum, который входит в состав стандартных операторов запросов, выполняет сравнение с нулем для поиска пустой последовательности или последовательности, содержащей только значения NULL. В LINQ to SQL семантика SQL остается неизменной, и при поиске пустой последовательности или последовательности, содержащей только значения NULL, метод Sum выполняет сравнение не с нулем, а со значением null.

Ограничения SQL для промежуточных результатов применяются к статистическим выражениям в LINQ to SQL. Результат метода Sum, суммирующего 32-разрядные целые значения, не вычисляется на основе 64-разрядных результатов. При преобразовании LINQ to SQL для метода Sum может произойти переполнение даже в том случае, если выполнение реализации стандартного оператора запроса для соответствующей последовательности в памяти не приводит к переполнению.

Аналогичным образом преобразование LINQ to SQL для метода Average, вычисляющего среднее значение целых чисел, возвращает тип integer, а не double.

Аргументы сущностей

Технология LINQ to SQL позволяет использовать в методах GroupBy и OrderBy типы сущностей. При преобразовании этих операторов использование аргумента типа рассматривается как указание всех членов данного типа. Ниже приведены примеры эквивалентного кода.

db.Customers.GroupBy(Function(c) c)
db.Customers.GroupBy(Function(c) New With {c.CustomerID, _
    c.ContactName})
db.Customers.GroupBy(c => c);
db.Customers.GroupBy(c => new { c.CustomerID, c.ContactName });

Сравниваемые и проверяемые на равенство аргументы

Ниже перечислены методы, в реализации которых требуется равенство аргументов.

Contains

Skip<TSource>

Union

Intersect

Except

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

Ниже представлены примеры плоских аргументов.

db.Customers.Select(Function(c) c)
db.Customers.Select(Function(c) New With {c.CustomerID, c.City})
db.Orders.Select(Function(o) New With {o.OrderID, o.Customer.City})
db.Orders.Select(Function(o) New With {o.OrderID, o.Customer})
db.Customers.Select(c => c);
db.Customers.Select(c => new { c.CustomerID, c.City });
db.Orders.Select(o => new { o.OrderID, o.Customer.City });
db.Orders.Select(o => new { o.OrderID, o.Customer });    

Ниже представлены примеры аргументов, не являющихся плоскими (иерархических аргументов).

' In the following line, c.Orders is a sequence.
db.Customers.Select(Function(c) New With {c.CustomerID, c.Orders})
' In the following line, the result has a sequence.
db.Customers.GroupBy(Function(c) c.City)
// In the following line, c.Orders is a sequence.
db.Customers.Select(c => new { c.CustomerID, c.Orders });
// In the following line, the result has a sequence.
db.Customers.GroupBy(c => c.City);

Преобразование функций Visual Basic

Ниже перечислены используемые компилятором Visual Basic вспомогательные функции, которые преобразуются в соответствующие операторы и функции SQL.

CompareString

DateTime.Compare

Decimal.Compare

IIf (in Microsoft.VisualBasic.Interaction)

Методы преобразования:

ToBoolean

ToSByte

ToByte

ToChar

ToCharArrayRankOne

ToDate

ToDecimal

ToDouble

ToInteger

ToUInteger

ToLong

ToULong

ToShort

ToUShort

ToSingle

ToString

Поддержка наследования

Ограничения сопоставления при наследовании

Дополнительные сведения см. в разделе Как сопоставить иерархии наследования (LINQ to SQL).

Наследование в запросах

В проекции поддерживаются только приведения типов C#. Приведения типов, используемые в других средах, пропускаются и не преобразуются. Помимо преобразования имен функций SQL, SQL фактически выполняет действия, эквивалентные операциям класса Convert среды CLR. Это означает, что SQL может изменить значение одного типа на значение другого типа. Здесь нет операции, эквивалентной приведению типов в среде CLR, поскольку отсутствует понятие повторной интерпретации тех же битов как битов другого типа. По этой причине приведение типов C# работает только на локальном компьютере. Оно не используется для удаленного взаимодействия.

Операторы is и as, а также метод GetType не ограничены оператором Select. Они могут использоваться также и в других операторах запроса.

Поддержка SQL Server 2008

Начиная с версии .NET Framework 3.5 с пакетом обновления 1 (SP1), LINQ to SQL поддерживает сопоставление с новыми типами даты и времени, впервые реализованными в SQL Server 2008. Однако операторы запросов LINQ to SQL, которые иногда используются при обработке значений, сопоставляемых с этими новыми типами, имеют определенные ограничения.

Неподдерживаемые операторы запросов

Следующие операторы запросов не поддерживаются для значений, сопоставляемых с новыми типами даты и времени SQL Server: DATETIME2, DATE, TIME и DATETIMEOFFSET.

  • Aggregate

  • Average

  • LastOrDefault

  • OfType

  • Sum

Дополнительные сведения о сопоставлении с этими типами даты и времени SQL Server см. в разделах Сопоставление типов SQL и CLR (LINQ to SQL).

Поддержка SQL Server 2005

LINQ to SQL не поддерживает следующие функции SQL Server 2005.

  • Хранимые процедуры, написанные для среды SQL CLR.

  • Пользовательский тип.

  • Функции запросов XML.

Поддержка SQL Server 2000

На поддержку LINQ to SQL влияют следующие ограничения SQL Server 2000 (по сравнению с Microsoft SQL Server 2005).

Операторы "Cross Apply" и "Outer Apply"

Эти операторы недоступны в SQL Server 2000. Технология LINQ to SQL пытается выполнить ряд операций перезаписи, чтобы заменить их соответствующими объединениями.

Операторы Cross Apply и Outer Apply создаются для перехода по отношениям. Набор запросов, для которого такие операции перезаписи возможны, не является правильно определенным. По этой причине минимальным набором запросов, поддерживаемым для SQL Server 2000, является набор, который не включает переходов по отношениям.

text / ntext

Типы данных text / ntext не могут использоваться в некоторых операциях запросов для значений varchar(max) / nvarchar(max), которые поддерживаются приложением Microsoft SQL Server 2005.

Способов разрешения проблем, связанных с этим ограничением, не существует. В частности, метод Distinct() нельзя использовать для результата, который содержит члены, сопоставленные с text или ntext.

Поведение, инициируемое вложенными запросами

Средство привязки SQL Server 2000 (входящее в состав пакета обновления 4 (SP4)) обладает некоторыми особенностями поведения, которые инициируются вложенными запросами. Набор запросов SQL, которые инициируют эти особенности, не является правильно определенным. По этой причине невозможно определить набор запросов LINQ to SQL, которые могут вызывать исключения SQL Server.

Операторы "Skip" и "Take"

На методы Take<TSource> и Skip<TSource> накладываются некоторые ограничения при их использовании в запросах для SQL Server 2000. Дополнительные сведения см. в подразделе "Исключения операторов "Skip" и "Take" в SQL Server 2000" раздела Устранение неполадок (LINQ to SQL).

Материализация объектов

Материализация создает объекты среды CLR из строк, возвращаемых одним или несколькими запросами SQL.

  • Следующие вызовы выполняются локально в составе процесса материализации.

    • Конструкторы

    • Методы ToString в проекциях

    • Приведения типов в проекциях

  • Методы, которые следуют за методом AsEnumerable<TSource>, выполняются локально. Этот метод не приводит к немедленному выполнению.

  • В качестве типа возвращаемых данных результата запроса или члена типа результата можно использовать значение struct. Сущности должны быть классами. Анонимные типы материализуются как экземпляры классов, но в проекциях можно использовать структуры (не сущности).

  • Член типа возвращаемых данных может быть типом, реализующим интерфейс IQueryable<T>. Он материализуется как локальная коллекция.

  • Ниже приведены методы, которые вызывают немедленную материализацию последовательности, к которой применяются эти методы.

См. также

Задачи

Как возвращать или пропускать элементы последовательности (LINQ to SQL)

Как объединить две последовательности (LINQ to SQL)

Как возвратить различия в наборах двух последовательностей (LINQ to SQL)

Как вернуть набор пересечения двух последовательностей (LINQ to SQL)

Как возвратить объединение наборов двух последовательностей (LINQ to SQL)

Другие ресурсы

Справочник (LINQ to SQL)