Какие методы закрыть скомпилированный запрос

Как мы знаем, вы не можете добавить дополнительный пункт, как .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
Другие вопросы по тегам