Понимание.AsEnumerable () в LINQ к SQL

Учитывая следующий LINQ к SQL-запросу:

var test = from i in Imports
           where i.IsActive
           select i;

Интерпретируемый SQL-оператор:

SELECT [t0].[id] AS [Id] .... FROM [Imports] AS [t0] WHERE [t0].[isActive] = 1

Скажите, что я хотел выполнить некоторое действие в выборе, который не может быть преобразован в SQL. Его мое понимание, что стандартный способ выполнить это состоит в том, чтобы сделать AsEnumerable() таким образом преобразовывая его в осуществимый объект.

Учитывая этот обновленный код:

var test = from i in Imports.AsEnumerable()
           where i.IsActive
           select new 
           { 
               // Make some method call 
           };

И обновленный SQL:

SELECT [t0].[id] AS [Id] ... FROM [Imports] AS [t0] 

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

Это означает, что вся таблица "Imports" кэшируется в память? Это замедлило бы производительность вообще, если бы таблица содержала большую сумму записей?

Помогите мне понять то, что на самом деле происходит негласно здесь.

44
задан abatishchev 6 August 2010 в 12:02
поделиться

3 ответа

Причина для AsEnumerable - это

AsEnumerable (TSource) (IEnumerable (TSource)) можно использовать для выбора между запросом реализации, когда последовательность реализует IEnumerable (T), но также имеет другой набор публичных запросов доступные методы

Итак, когда вы раньше вызывали метод Where , вы вызывали другой метод Where из IEnumerable.Where . Этот оператор Where был для LINQ для преобразования в SQL, новый Где - это IEnumerable , который принимает IEnumerable , перечисляет его и дает совпадающие элементы. Это объясняет, почему вы видите, что генерируется другой SQL. Таблица будет полностью взята из базы данных до того, как расширение Где будет применено во второй версии кода. Это может создать серьезное узкое место, потому что вся таблица должна находиться в памяти или, что еще хуже, вся таблица должна перемещаться между серверами. Разрешить серверу SQL выполнить Где и делать то, что у него лучше всего получается.

34
ответ дан 26 November 2019 в 22:19
поделиться

Я считаю, что AsEnumerable просто сообщает компилятору, какие методы расширения использовать (в данном случае те, которые определены для IEnumerable, а не для IQueryable). Выполнение запроса по-прежнему откладывается до тех пор, пока вы не вызовете ToArray или не перечислите его.

2
ответ дан 26 November 2019 в 22:19
поделиться

В тот момент, когда перечисление выполнено, будет сделан запрос к базе данных и получен весь набор результатов.

Решением может быть частичное решение. Рассмотрим

var res = (
    from result in SomeSource
    where DatabaseConvertableCriterion(result)
    && NonDatabaseConvertableCriterion(result)
    select new {result.A, result.B}
);

Допустим также, что NonDatabaseConvertableCriterion требует поле C из результата. Поскольку NonDatabaseConvertableCriterion делает то, что следует из его названия, это должно быть выполнено как перечисление. Однако, подумайте:

var partWay =
(
    from result in SomeSource
    where DatabaseConvertableCriterion(result)
    select new {result.A, result.B, result.C}
);
var res =
(
    from result in partWay.AsEnumerable()
    where NonDatabaseConvertableCriterion select new {result.A, result.B}
);

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

7
ответ дан 26 November 2019 в 22:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: