Доступ к 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, соединение уже было закрыто.