Вопрос

Учитывая следующий запрос LINQ to 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] 

Обратите внимание на отсутствие предложенияwhere в исполняемом операторе SQL.

Означает ли это, что вся таблица «Импорт» кэшируется в памяти?Будет ли это снижать производительность вообще, если таблица будет содержать большое количество записей?

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

Это было полезно?

Решение

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

Asenumerable (Tsource) (Ienumerable (Tsource)) может использоваться для выбора между реализациями запросов, когда последовательность реализует Ienumerable (t), но также имеет другой набор доступных методов общественного запроса

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

Другие советы

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

решение для деталей может быть способом.Рассмотрим

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

Скажем также, что nondatabaseconvertablecriterite требует поля 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 перечислен, запрашивается или иным образом используется, как можно больше работать, будет передаваться в базу данных, которая будет возвращаться достаточно, чтобы продолжить работу.Предполагая, что действительно действительно невозможно переписать, чтобы вся работа была отправлена в базу данных, это может быть подходящий компромисс.

Существует три реализации AsEnumerable.

DataTableExtensions.AsEnumerable

Расширяет DataTable чтобы дать этому IEnumerable интерфейс, чтобы вы могли использовать Linq для DataTable.

Enumerable.AsEnumerable<TSource> и ParallelEnumerable.AsEnumerable<TSource>

А AsEnumerable<TSource>(IEnumerable<TSource>) Метод не влияет, кроме как изменить тип источника времени компиляции из типа, который реализует IEnumerable<T> к IEnumerable<T> сам.

AsEnumerable<TSource>(IEnumerable<TSource>) можно использовать для выбора между реализациями запросов, когда внедряет последовательность IEnumerable<T> но также имеет другой набор доступных методов общественного запроса.Например, учитывая общий класс Table который реализует IEnumerable<T> и имеет свои собственные методы, такие как Where, Select, и SelectMany, звонок в Where призовет общественность Where метод TableTable тип, представляющий таблицу базы данных, может иметь Where Метод, который принимает аргумент предиката как дерево выражения и преобразует дерево в SQL для удаленного выполнения.Если удаленное выполнение не требуется, например, потому что предикат вызывает локальный метод, AsEnumerable<TSource> Метод может использоваться для скрытия пользовательских методов и вместо этого сделать стандартные операторы запроса доступными.

Другими словами.

Если у меня есть

IQueryable<X> sequence = ...;

из LinqProvider, например Entity Framework, и я это делаю,

sequence.Where(x => SomeUnusualPredicate(x));

этот запрос будет составлен и запущен на сервере.Это не удастся во время выполнения, поскольку EntityFramework не знает, как преобразовать SomeUnusualPredicate в SQL.

Если я хочу, чтобы вместо этого запускался оператор с помощью Linq to Objects, я так и делаю:

sequence.AsEnumerable().Where(x => SomeUnusualPredicate(x));

теперь сервер вернет все данные и Enumerable.Where from Linq to Objects будет использоваться вместо реализации поставщика запросов.

Не имеет значения, что Entity Framework не знает, как интерпретировать SomeUnusualPredicate, моя функция будет использоваться напрямую.(Однако это может оказаться неэффективным подходом, поскольку все строки будут возвращены с сервера.)

Я считаю, что aseNumerable просто говорит компилятору, что методы расширения для использования (в этом случае, которые определяются для iEnumerable вместо их для iQueryable). Выполнение запроса по-прежнему отложено до тех пор, пока вы не вызовите Toarlay или не перечисляете на него.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top