Как определить, какие функции Linq не будут вызывать в sql несколько раз?

            var costCenters = from c in dbContext.CostCenters //no sql call here
                          orderby c.DisplayRank descending
                          select c;


            List lstCostCenter = costCenters.ToList();//Immediate execution to sql the first time

            lstCostCenter = costCenters.ToList();//no Sql call ??

            int test = costCenters.Count();//Call Sql everytime
            test = costCenters.Count();//Call Sql again???

Я использую Entity Framework 5

Я начинаю изучать Linq. Я действительно смущен тем, какие функции быстрого выполнения будут вызывать SQL каждый раз. Как вы можете видеть в приведенном выше примере, как ToList (), так и Count() являются непосредственной функцией выполнения, но только Count() будет подключаться к sql при вызове подпоследовательности. ToList() подключается к sql 1 раз, но Count() будет подключаться к Sql каждый раз.
Как определить, какие функции linq не будут обращаться к sql несколько раз?

4
добавлено отредактировано
Просмотры: 2
nl ja de

3 ответы

Прежде всего, ToList() никогда не использует отложенное выполнение. Он всегда актуализирует информацию сразу. Он не постоянно возвращается к базе данных каждый раз, потому что уже захватил все сущности.

Чтобы узнать, какие операторы что-то делают, просто посмотрите по этой ссылке .

4
добавлено
Но если EF не нужно переходить к SQL для второго ToList , зачем это нужно для второго Count ?
добавлено автор Rawling, источник
+1 для отличной ссылки
добавлено автор Sergey Berezovskiy, источник
Not ToList, нет, поскольку все, что ему нужно сделать, это захватить все записи сами. Как только все записи будут загружены, EF не сможет вернуться к SQL, поскольку запрос уже загружен.
добавлено автор IronMan84, источник
Из ссылки, которую вы мне предоставили, как ToList (), так и Count() классифицируются как Immediate Execution. На веб-сайте: немедленное выполнение означает, что источник данных считывается, и операция выполняется в точке кода, в котором объявлен запрос. Все стандартные операторы запроса, которые возвращают один, неперечислимый результат, выполняются немедленно. Таким образом, не следует, чтобы оба метода ToList() и Count() обращались к sql каждый раз при их вызове?
добавлено автор gavin, источник
Благодаря вам, указывая на то, что они выполняются незамедлительно, я, наконец, смог ответить на этот вопрос, разница заключается в том, что операторы преобразования, такие как tolist() или toarray (), делают копию результата и позволяют получить к нему доступ столько раз, сколько вам нравится по этой ссылке: dotnetcurry.com/ShowArticle.aspx?ID=750</а>
добавлено автор gavin, источник

Разница заключается в том, что при первом вызове ToList() он преобразует IQueryable (который является просто определением запроса) в список IEnumerable (запрос к базе данных). Другими словами, вы возвращаете список объектов, которые теперь находятся в памяти, поэтому любые последующие вызовы LINQ в результирующем списке используют версию IEnumerable, которая работает с объектами в памяти. Кроме того, EF имеет функцию, которая кэширует результаты, поэтому, даже если вы вызываете ToList на исходную ссылку IQueryable, скорее всего, будут использовать объекты in-memory вместо того, чтобы извлекать их из базы данных. Я угадываю , что граф снова обращается к базе данных, а не подсчитывает результаты кэширования, потому что запрос для подсчета - это не тот же запрос для ToList (это тип агрегата/группировки), а также, возможно, он разработан таким образом, потому что механизм БД более эффективен при подсчете.

В вашем примере costCenters является IQueryable, потому что все, что вы делаете, - это определить запрос, но еще не называть ToList. lstCostCenter - это IEnumerable, представляющий результаты в памяти в результате запроса после выполнения с помощью ToList. Обычно немедленные вызовы, которые дают результаты, .Count, .ToList и т. Д., Когда выполняется в IQueryable, приведут к вызову БД (исключение - когда он находит кешированные результаты, которые он может повторно использовать) и вызывает объект IEnumerable (в вашем случае lstCostCenter ) будет работать в памяти.

To get more predictable results, then call ToList on the IQueryable first, and make all further calls on the IEnumerable. In other words, anything you call on lstCostCenter is guaranteed not to hit the database. This is usually the best way to handle it, except if you expect the resulting lists to be large. For example, if lstCostCenter ended up with a 10,000 objects, you probably wouldn't then want to do lstCostCenter.Where(x=>x.Blah > 5) because that would loop over all 10,000 objects in memory to filter them. In such a case it would be better to modify the query first by appending the additional call to the IQueryable and then calling ToList so that we leverage the DB engine which is better at handling large sets: costCenters.Where(x=>x.Blah > 5).ToList().

3
добавлено
После дальнейших чтений я понимаю, что кеширование осуществляется посредством «принудительного исполнения»,
добавлено автор gavin, источник

http://msdn.microsoft.com/en-us/library/bb738633.aspx

Разница заключается в «Принудительном исполнении». Если вы принудительно выполняете запрос, вы кешируете результат. И операторы преобразования, такие как ToList (), ToArray() и даже foreach, классифицируются как принудительное выполнение, поэтому дальнейший вызов будет работать только в кэше памяти. Где, как Count (), First (), Max() и Average (), не рассматриваются как принудительное выполнение ... Они являются частью запроса ... Думаю.

1
добавлено