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


Перевод стандартных операторов запросов

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

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

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

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

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

Конкатенировать

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

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

Пересечение, Исключение, Объединение

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

Этот Union метод определяется для нескольких наборов как неупорядоченное объединение нескольких наборов (фактически результат предложения UNION ALL в SQL).

Принять, пропустить

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-разрядных результатов. Может возникнуть переполнение для преобразования Sum LINQ 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 в основном выполняет эквивалент среды выполнения общего языка CLR Convert. То есть 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, , DATETIMEи 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, — это набор, который не включает навигацию по связям.

текст / Nтекст

Типы данных 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>. Она представляется как локальная коллекция.

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

См. также