Обновление - ответ, по-видимому, который не реализует 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
, и это - единственное время, которым это называют.
Так, три вопроса:
DataContext
все еще запросите базу данных для результатов после DataContext
был расположен?Dispose()
на самом деле?DataContext
, но мое впечатление было то, что это не плохая идея. Есть ли любая причина не избавиться от DbLinq DataContext
?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
, не забудьте его утилизировать.
"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
Глубоко внутри API вы, вероятно, увидите метод, использующий api, подобный этому:
http://msdn.microsoft.com/en-us/library/y6wy5a0f (v = VS.100) .aspx
Когда команда выполняется, связанный объект Connection закрывается, когда закрывается связанный объект DataReader.