Использование результата запроса sql linq приводит к тому, что база данных дважды запрашивается - PullRequest
1 голос
/ 22 декабря 2011

Я запрашиваю базу данных и отправляю результат на консоль и в файл, используя два метода:

var result = from p in _db.Pages
             join r in rank on p.PkId equals r.Key
             orderby r.NumPages descending
             select new KeyNameCount
                                    {
                                        PageID = p.PkId,
                                        PageName = p.Name,
                                        Count = r.NumPages
                                    };

WriteFindingsToFile(result, parentId);
WriteFindingsToConsole(result, parentId);

IEnumerable , а не IQuerable используется как тип параметра для результата при использовании в качестве параметра в двух вызовах метода.

В обоих вызовах результат повторяется в foreach. Это приводит к двум одинаковым вызовам в базе данных, по одному для каждого метода.

Я мог бы преобразовать два метода в один и использовать только один foreach, но это быстро стало бы очень трудно поддерживать (добавление записи в HTML, записи в XML и т. Д.)

Я почти уверен, что это довольно распространенный вопрос, но использование Google не сделало меня мудрее, поэтому я обращаюсь к вам, ребята: -)

Ответы [ 3 ]

6 голосов
/ 22 декабря 2011

Каждый раз, когда вы получаете доступ к запросу LINQ, он запрашивает базу данных для обновления данных.Чтобы остановить это, используйте .ToArray() или .ToList().

например,

var result = (from p in _db.Pages
             select p).ToList(); //will query now

Write(result);  //will not requery
Write(result2); //will not requery

Важно понимать, что необработанный запрос LINQ выполняется, когда он используется, а не когда он записан вкод (например, не утилизируйте ваш _db до этого).

Это может быть удивительно, когда вы понимаете, как это действительно работает.Это позволяет отразить цепочку методов и последующую модификацию запроса в последнем выполнении запроса в БД.Важно всегда помнить, так как это может привести к ошибкам во время выполнения, которые не будут обнаружены во время компиляции, обычно потому, что соединение с БД закрыто до использования списка, так как вы передаете то, что кажется простым IEnumerable.

РЕДАКТИРОВАТЬ: Изменено, чтобы удалить мое мнение и отразить обсуждение в комментариях.Лично я думаю, что компилятор должен предполагать, что конечный результат связанных запросов запускается немедленно, если вы явно не скажете, что он будет дополнительно изменен позже.Просто чтобы избежать ошибок во время выполнения, это неизбежно вызывает.

2 голосов
/ 22 декабря 2011

Если вы посмотрите на определение функции для IQuerayble , вы увидите, что оно также реализует IEnumerable.Таким образом, вы можете передать IQueryable в качестве параметра функции IEnumerable без фактического его перечисления.

Но из-за отложенного шаблона выполнения Linqs IQueryable будет выполняться только для базы данных, когда вы выполняете его итерацию (с циклом for дляпример, как в вашем случае, или с ToList () или функциями вроде First / Single).

Вот сообщение в блоге , которое объясняет, как это работает.

Если выизменив код на следующий, вы попадете в базу данных только один раз, а затем передадите результат в память своим функциям:

var result = (from p in _db.Pages
             join r in rank on p.PkId equals r.Key
             orderby r.NumPages descending
             select new KeyNameCount
                                    {
                                        PageID = p.PkId,
                                        PageName = p.Name,
                                        Count = r.NumPages
                                    }).ToList();

WriteFindingsToFile(result, parentId);
WriteFindingsToConsole(result, parentId);
0 голосов
/ 22 декабря 2011

Каждый раз, когда вы перебираете свой результат LINQ, база данных также будет запрашиваться.

Это называется Отложенное выполнение запроса .Вы можете глубже изучить одну (из многих) соответствующих MSDN статей!

Execution of the query is deferred until the query variable is iterated over in a foreach or For Each loop

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...