Доступ к DataContext после утилизации
Я использую ASP.NET 4.0.
У меня есть следующий код, который возвращается с ошибкой "Не удается получить доступ к удаленному объекту.
Имя объекта: "Доступ к DataContext после Dispose.".
public IEnumerable<BatchHeader> GetHeaders()
{
using(NSFChecksDataContext context = DataContext)
{
IEnumerable<BatchHeader> headers = (from h in context.BatchHeaders
select h);
return headers;
}
}
Если я изменил это на:
public IEnumerable<BatchHeader> GetHeaders()
{
using(NSFChecksDataContext context = DataContext)
{
return context.BatchHeaders.ToList();
}
}
Все будет хорошо. Я использую этот метод для заполнения RadGrid. Может кто-нибудь объяснить, почему второй метод будет работать, но не первый?
Спасибо.
Ответы
Ответ 1
Первое не работает, потому что когда метод возвращает контекст данных, созданный в блоке using
, удаляется. Однако возвращаемый IEnumerable<BatchHeader>
лениво оценивается и нуждается в том, чтобы этот контекст данных был живым, чтобы перечислять его результаты.
Вы можете сделать что-то вроде этого:
public IEnumerable<BatchHeader> GetHeaders() {
using(NSFChecksDataContext context = DataContext) {
foreach(var header in context.BatchHeaders) {
yield return header;
}
}
}
Второй блок работает, потому что результаты запроса перечисляются и сохраняются в памяти до того, как удаляется контекст данных. После этого контекст данных больше не нужен. Однако будьте осторожны при использовании кода, такого как ваш второй блок; если таблица BatchHeaders
велика, вы просто потянули ее все в память.
Теперь, и вот самая серьезная часть моего ответа: Я абсолютно не могу видеть запросы, которые создают экземпляры данных для выполнения. Я хочу знать и контролировать, когда используются мои контексты данных.
Ответ 2
Я предполагаю, что IEnumerable из вашего контекста использует отложенное выполнение, поэтому, если вы не заставляете его перечислять с помощью ToList, он не делает этого до тех пор, пока вы не будете использовать значения, которые в этом случае находятся за пределами используемого блока, поэтому объект будет удален.
Ответ 3
return headers.AsEnumerable();
должен работать, потому что по умолчанию запрос linq возвращает объект IQueryable, что означает, что данные не извлекаются из db до тех пор, пока не будут перечислены с использованием foreach, ToArray, ToList или AsEnumerable. Когда Asp.Net попытался получить доступ к IQueryable и получить данные, используя foreach, соединение уже было закрыто.