Почему возможно перечислить запрос DbLinq после того, как вызов Расположит () на DataContext?

Обновление - ответ, по-видимому, который не реализует DbLinq Dispose() правильно. D'oh!


Ниже весь вид введения в заблуждение - Нижняя строка: DbLinq еще не эквивалентен LinqToSql, поскольку я принял, когда я первоначально задал этот вопрос. Используйте его с осторожностью!

Я использую Шаблон Репозитория с DbLinq. Моя реализация объектов репозитария IDisposable, и Dispose() метод делает только вещь - вызовы Dispose() на DataContext. Каждый раз, когда я использую репозиторий, я переношу его в a using блок, как это:

public IEnumerable SelectPersons()
{
    using (var repository = _repositorySource.GetPersonRepository())
    {
        return repository.GetAll(); // returns DataContext.Person as an IQueryable
    }
}

Этот метод возвращается IEnumerable, таким образом, если мое понимание корректно, никакие запросы базы данных на самом деле не происходят до Enumerable пересечен (например, путем преобразования его в список или массив или при помощи его в a foreach цикл), как в этом примере:

var persons = gateway.SelectPersons();
// Dispose() is fired here
var personViewModels = (
    from b in persons
    select new PersonViewModel
    {
        Id = b.Id,
        Name = b.Name,
        Age = b.Age,
        OrdersCount = b.Order.Count()
    }).ToList(); // executes queries

В этом примере, Dispose() сразу назван после установки persons, который является IEnumerable, и это - единственное время, которым это называют.

Так, три вопроса:

  1. Как это работает? Как может склонное DataContext все еще запросите базу данных для результатов после DataContext был расположен?
  2. Что делает Dispose() на самом деле?
  3. Я услышал, что это не необходимо (например, посмотрите этот вопрос) избавляться от a DataContext, но мое впечатление было то, что это не плохая идея. Есть ли любая причина не избавиться от DbLinq DataContext?

8
задан Community 23 May 2017 в 11:47
поделиться

3 ответа

1 Как это работает? Как может утилизированный DataContext продолжать запрашивать результаты у базы данных после того, как DataContext был утилизирован?

Это не работает. Вы что-то не показываете. Я предполагаю, что либо ваш класс репозитория не утилизирует DataContext правильно/в нужное время, либо вы перфектно пишете ToList() в конце каждого запроса, что полностью сводит на нет преобразование запроса и отложенное выполнение, которое вы обычно получаете.

Попробуйте следующий код в тестовом приложении, я гарантирую вам, что он выбросит ObjectDisposedException:

// Bad code; do not use, will throw exception.
IEnumerable<Person> people;
using (var context = new TestDataContext())
{
    people = context.Person;
}
foreach (Person p in people)
{
    Console.WriteLine(p.ID);
}

Это самый простой из возможных воспроизводимых случаев, и он всегда будет выбрасываться. С другой стороны, если вместо этого написать people = context.Person.ToList(), то результаты запроса уже будут перечислены внутри блока using, что, я уверен, и происходит в вашем случае.

2 Что на самом деле делает Dispose()?

Среди прочего, она устанавливает флаг, указывающий на то, что DataContext утилизирован, который проверяется при каждом последующем запросе и заставляет DataContext выбросить ObjectDisposedException с сообщением Object name: 'DataContext accessed after Dispose.'.

Он также закрывает соединение, если DataContext открыл его и оставил открытым.

3 Я слышал, что утилизировать DataContext не обязательно (например, см. этот вопрос), но у меня сложилось впечатление, что это неплохая идея. Есть ли причины не утилизировать LinqToSql DataContext?

Необходимо утилизировать утилизировать DataContext, как необходимо утилизировать каждый другой IDisposable. Потенциально возможна утечка соединений, если вы не сможете утилизировать DataContext. Также возможна утечка памяти, если какие-либо сущности, извлекаемые из DataContext, остаются живыми, поскольку контекст поддерживает внутренний кэш идентификаторов для реализуемого им шаблона единицы работы. Но даже если бы ничего этого не было, это не ваша забота, что делает метод Dispose внутри. Предположим, что он делает что-то важное.

IDisposable - это контракт, который говорит: "Очистка не может быть автоматической; вы должны утилизировать меня, когда закончите". У вас нет гарантий того, есть ли у объекта собственный финализатор, который уберет за вами, если вы забудете утилизировать. Реализации могут меняться, поэтому не стоит полагаться на наблюдаемое поведение, а не на явные спецификации.

Худшее, что может случиться, если вы утилизируете IDisposable с пустым методом Dispose - это то, что вы потратите несколько тактов процессора. Худшее, что может случиться, если вы не сможете утилизировать IDisposable с нетривиальной реализацией - это утечка ресурсов. Выбор здесь очевиден; если вы видите IDisposable, не забудьте его утилизировать.

3
ответ дан 6 December 2019 в 00:54
поделиться

"persons" - это коллекция IEnumerable, DataContext (хранилище) требуется только для выполнения вызова .GetNew.

ключевые слова from/select/etc являются синтаксическим сахаром для методов расширения, добавленных в пространство имен System.Linq. Эти методы расширения добавляют функциональность IEnumerable, которую вы используете в запросе, а не DataContext. Фактически, все это можно сделать вообще без использования LINQ2SQL, программно создав IEnumerable для демонстрации.

Если вы попытаетесь выполнить дальнейшие вызовы хранилища (DataContext), используя эти объекты, то получите ошибку.

Коллекция IEnumerable будет содержать ВСЕ записи из вашего хранилища, вот почему вам не требуется DataContext для выполнения запроса.

Методы расширения: http://msdn.microsoft.com/en-us/library/bb383977.aspx

Методы расширения LINQ: http://msdn.microsoft.com/en-us/library/system.linq.enumerable_members.aspx

0
ответ дан 6 December 2019 в 00:54
поделиться

Глубоко внутри API вы, вероятно, увидите метод, использующий api, подобный этому:

http://msdn.microsoft.com/en-us/library/y6wy5a0f (v = VS.100) .aspx

Когда команда выполняется, связанный объект Connection закрывается, когда закрывается связанный объект DataReader.

0
ответ дан 6 December 2019 в 00:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: