Поделиться через


Трансляция стандартных операторов запросов

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

Стандартные операторы запросов определяются для последовательностей. Последовательность упорядочена и зависит от ссылочного удостоверения для каждого элемента последовательности. Дополнительные сведения см. в обзоре стандартных операторов запросов (C#) или стандартном обзоре операторов запросов (Visual Basic).

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

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

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

Concat

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

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

Intersect, Except, Union

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

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

Take, Skip

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

Примечание.

На методы Take и Skip накладываются некоторые ограничения при их использовании в запросах для SQL Server 2000. Дополнительные сведения см. в статье "Пропуск и выполнение исключений в SQL Server 2000" в разделе "Устранение неполадок".

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

var custQuery =
    (from cust in db.Customers
    where cust.City == "London"
    orderby cust.CustomerID
    select cust).Skip(1).Take(1);
Dim custQuery = _
    From cust In db.Customers _
    Where cust.City = "London" _
    Order By 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 и Skip все указанные операции упорядочения должны быть согласованными. В противном случае результаты не определены.

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

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

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

Операторы Правильно
TakeWhile, SkipWhile SQL-запросы работают с мультинаборами и не работают с последовательностями. Атрибут ORDER BY должен быть последним предложением, применяемым к статистической функции. По этой причине преобразование общего назначения для этих двух методов отсутствует.
Reverse Перевод этого метода возможен для упорядоченного набора, но в настоящее время не преобразуется LINQ to SQL.
Last, LastOrDefault Перевод этих методов возможен для упорядоченного набора, но в настоящее время не преобразуется LINQ to SQL.
ElementAt, ElementAtOrDefault Запросы SQL работают с мультинаборами и не работают с индексируемыми последовательностями.
DefaultIfEmpty (перегрузка с аргументом по умолчанию) В общем случае значение по умолчанию для произвольного кортежа указать невозможно. В некоторых случаях для кортежей можно указать нулевые значения через внешние соединения.

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

Семантика NULL

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 });	
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})

Ниже приведены примеры неструктурированных (иерархических) аргументов:

// 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);
' 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)

Преобразование функций 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

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

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

Дополнительные сведения см. в разделе "Практическое руководство. Сопоставление иерархий наследования".

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

В проекции поддерживаются только приведения типов 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".

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

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

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

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

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

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

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

Операторы «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 (через sp4) содержит некоторые идиосинхразы, которые активируются вложенными запросами. Набор запросов SQL, которые инициируют эти особенности, не является правильно определенным. По этой причине невозможно определить набор запросов LINQ to SQL, которые могут вызвать исключения SQL Server.

Операторы «Skip» и «Take»

На методы Take и Skip накладываются некоторые ограничения при их использовании в запросах для SQL Server 2000. Дополнительные сведения см. в статье "Пропуск и выполнение исключений в SQL Server 2000" в разделе "Устранение неполадок".

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

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

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

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

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

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

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

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

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

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

См. также