Доходность возврата записей базы данных с использованием LinqToSql? - PullRequest
5 голосов
/ 17 февраля 2012

У меня есть способ доставки в DAL:

public IEnumerable<RecordType> GetRecords()
{
    using (LinqDataContext context = new LinqDataContext())
    {
        var records = context.RecordTable;

        foreach (RecordType record in records)
        {
            yield return record;
        }
    }
}

Метод-потребитель использует записи в цикле foreach. Таким образом, я хочу сохранить использование памяти, не кэшируя все записи из RecordTable, поскольку LinqToSql использует DataReader за сценой.

У меня есть два вопроса по этому сценарию:

  1. Правда ли, что возвращение выхода выше экономит ресурсы и работает быстрее, чем кэширование всех записей в массив (.ToArray ())?

  2. Будет ли соединение данных автоматически автоматически закрыто (я имею в виду оператор using), если произойдет ошибка внутри цикла foreach метода-потребителя ИЛИ если метод-потребитель прервет цикл foreach посередине (вроде нашли нужную запись и break)?

Ответы [ 3 ]

3 голосов
/ 17 февраля 2012

В случае выполнения базового запроса он может работать таким образом (конечно, это возможно) - однако, в случае запроса голого Table<T>, он может будь то, что все это буферизует первым;Вы можете попробовать запросить счетчик во время итерации или запустить трассировку.В этом случае я подозреваю , что он сначала буферизуется.

Повторно закрыто: это также зависит; p Если кто-то использует foreach, тогда да: поскольку foreach явно выводит итератор черезfinally.Тем не мение!Не гарантируется, если кто-то, например, (очень непослушный и слабый):

var iter = yourData.GetEnumerator();
if(iter.MoveNext()) {
    Console.WriteLine(iter.Current.Name); // first record of, say, 20
}
// and don't dispose the iterator == bad

тогда, так как итератор не a: получает распоряжение, b: исчерпывает себя, и c: не падает, он не отключится должным образом (любое из этих 3 условий будет правильно его закрывать).Подчеркивание: это патологический случай: обычно достаточно безопасно сказать «он закроется, да».

Если вы хотите гарантированную небуферизацию, учтите, что «dapper» имеет это, если вы установите buffered до false:

IEnumerable<Customer> customers = connection.Query<Customer>(
       "select * from Customer", buffered: false);

(он также может обрабатывать параметры и т. д.)

3 голосов
/ 17 февраля 2012

1) yield не обязательно будет быстрее получать все значения, но это позволит коду начать обработку результатов до того, как база данных вернет все результаты. То есть, yield возвращает первый результат в тот момент, когда он появляется, в то время как ToArray () должен ждать, пока все результаты не появятся, прежде чем вернуться. Конечно, если базовые провайдеры возвращают все результаты сразу из-за буферизации или по другим причинам, это может не иметь значения.

2) Да, using будет распоряжаться LinqDataContext независимо от того, как вы выходите из блока using (исключения / возврат / прерывание /...)

2 голосов
/ 17 февраля 2012
  1. Итератор будет лениво оцениваться. Он вытянет первый товар, а затем «отдаст» его потребителю. Влияние на производительность будет зависеть от того, как реализован LinqDataContext (он может кэшировать содержимое внутри). Использование ToArray () или ToList () заставит все элементы выйти из LinqDataContext, прежде чем продолжить. Следовательно, использование ToArray () не даст вам ничего, пока LinqDataContext не вернет каждый элемент. Будет ли это оптимальным или нет, решать только вам.
  2. Да, «использование» будет принудительно применено.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...