Какие методы закрыть скомпилированный запрос - PullRequest
3 голосов
/ 16 июля 2010

Как мы знаем, вы не можете добавить дополнительное предложение типа .Where() или .First() к скомпилированному запросу, потому что это изменяет запрос и вызывает перекомпиляцию.Я хотел бы знать, какие методы можно использовать для «закрытия» скомпилированного запроса.

Я знаю, что большинство людей используют либо .AsEnumerable(), либо .ToList(), но какие другие методы также работают?Могу ли я использовать .AsQueryable(), или это не работает?

И что лучше с точки зрения производительности?Я знаю, что .AsEnumerable() быстрее, чем .ToList(), но если я хочу IQueryable, будет .AsEnumerable().AsQueryable() лучше, чем .ToList()?

Ответы [ 2 ]

7 голосов
/ 26 июля 2010

В большинстве случаев AsEnumerable().AsQueryable(), вероятно, то, что вы хотите, потому что:

  • Делая явное AsEnumerable(), вы не рискуете из-за того, что базовая реализация превращает AsQueryable() в бездействие, тем самым разрушая вашу попытку закрыть запрос. Я не говорю, что сегодняшний EF делает AsQueryable() бездействующим (насколько я могу судить, это не так), только то, что поведение - бездействие или прозрачный вызов AsEnumerable () - isn ' Это задокументировано, поэтому полагаться на это небезопасно.
  • AsEnumerable(), в отличие от ToList(), не загружает весь ваш набор результатов в память для его запроса. Это имеет большое значение для больших наборов результатов. Теоретически возможно, что для небольших наборов результатов может быть какое-то преимущество использования ToList () (например, оптимизированная реализация ToList () извлекает данные большими порциями из базового поставщика, в то время как перечисление требует большего переключения контекста), но это кажется маловероятным и трудным для понимания. зависит от разных поставщиков и версий, в то время как преимущество AsEnumerable () для большого набора результатов будет существовать вечно.

Единственный случай, когда мне нравится вызывать ToList(), - это когда я явно хочу принудительно выполнить запрос прямо сейчас. Например, если я хочу поймать ошибки в запросе ранее в методе, чтобы потом можно было упростить обработку ошибок, или я хочу проверить все базовые данные, прежде чем продолжить с остальной частью запроса. Или, если запрос легче тестировать, когда он разбит на две части. И я никогда не буду этого делать, если не буду знать, что мой набор записей будет небольшим, поскольку вызов ToList () для запроса с несколькими миллионами строк убьет вашу оперативную память.

Чтобы ответить на другой ваш вопрос, Преобразование типов данных в документации LINQ по MSDN подробно описывает, какие методы LINQ принудительно выполняют запрос. Согласно этой странице, ToArray(), ToDictionary(), ToList() и ToLookup() все принудительно выполняют запрос.

AsEnumerable (), напротив, не вызывает немедленного выполнения запроса, но "закрывает" запрос (используя здесь ваш термин, не уверен, что для этого есть официальный термин). За http://msdn.microsoft.com/en-us/library/bb335435.aspx:

может метод AsEnumerable использоваться, чтобы скрыть пользовательские методы и вместо этого сделайте стандартный запрос операторы доступны.

Другими словами, запуск AsEnumerable заставит все вызовы, такие как Take() и Where(), использовать универсальные реализации LINQ, а не anythign custom, что приведет к повторной компиляции.

1 голос
/ 11 ноября 2013

какие методы можно использовать для "закрытия" скомпилированного запроса.

Методы, которые возвращают последовательность, используют отложенное выполнение, если только метод не похож на ToXYZ.Where, Select, Take, Skip, GroupBy и OrderBy и т. Д. Подпадают под это.Методы, которые возвращают один объект, вызывают выполнение запроса, например First, Single, ToList и ToArray, ToDictionary, ToLookup, Any, All и т. Д.подробнее: Linq - Какой самый быстрый способ узнать отложенное выполнение или нет?

Я знаю, что большинство людей используют либо .AsEnumerable (), либо .ToList (), но которыедругие методы работают так же?Могу ли я использовать .AsQueryable (), или это не работает?

Они все разные.У Джастина есть грандиозное объяснение.Вы также можете захотеть увидеть: В чем разница между .ToList (), .AsEnumerable (), AsQueryable ()? с хорошим ответом.


ВВ общем, вы можете понять семантику метода, увидев имя самого метода.Метод с именем AsSomething подразумевает, что он ничего не делает, но возвращает ввод как нечто .Это может включать или не включать возвращение нового объекта, но ссылка как-то поддерживается.Например, List<T>.AsEnumerable() просто выполняет приведение к IEnumerable<T> (конечно, это имеет большее значение в контексте linq).Вы можете привести его обратно к List<T> и изменить его, отражая изменения повсюду.Чтобы проверить это:

var list = new List<int> { 1, 2 };
var enum = list.AsEnumerable();
var newlist = enum as List<string>;
newlist.Add(3);
//print enum.Count() -> 3

Хотя методы выглядят как ToSomething, вы получаете совершенно новый объект, часто преобразуемый во что-то другое.

var list = new List<int> { 1, 2 };
var newlist = list.ToList();
newlist.Add(3);
//print list.Count -> 2

Давайте рассмотрим что-то вне контекста linq.object.ToString() приводит к новому представлению строки (строки в любом случае неизменны, так что это немного бессмысленно).Интересная семантика - это List<T>.AsReadonly, которая возвращает новый ReadOnlyCollection<T> экземпляр, но изменение списка за его пределами также изменяет внутренний список ReadOnlyCollection<T>, поэтому имя AsReadonly.

var list = new List<int> { 1, 2 };
var readonlylist = list.AsReadonly();
list.Add(3);
//print readonlylist.Count -> 3
...