Какие методы закрыть скомпилированный запрос
Как мы знаем, вы не можете добавить дополнительный пункт, как .Where()
или же .First()
на скомпилированный запрос, потому что это изменяет запрос и вызывает перекомпиляцию. Я хотел бы знать, какие методы можно использовать для "закрытия" скомпилированного запроса.
Я знаю, что большинство людей используют либо .AsEnumerable()
или же .ToList()
, но какие еще методы работают? Могу ли я использовать .AsQueryable()
или это неоперация?
И что лучше по производительности? я знаю .AsEnumerable()
быстрее чем .ToList()
, но если я хочу IQueryable
, является .AsEnumerable().AsQueryable()
лучше чем .ToList()
?
2 ответа
В большинстве случаев, AsEnumerable().AsQueryable()
это, вероятно, то, что вы хотите, потому что:
- Делая явный
AsEnumerable()
вы не рискуете сделать основную реализациюAsQueryable()
в бездействие, тем самым разрушая вашу попытку закрыть запрос. Я не говорю, что сегодняшний EF делаетAsQueryable()
no-op (насколько я могу судить, это не так), только то, что поведение - no-op или прозрачный вызов AsEnumerable()- не задокументировано, поэтому полагаться на него небезопасно. 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, что может привести к повторной компиляции.
какие методы можно использовать для "закрытия" скомпилированного запроса.
Методы, которые возвращают последовательность, используют отложенное выполнение, если только метод не является чем-то вроде 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