Удаление текста данных приводит к недопустимой попытке вызова Read, когда читатель закрыт - PullRequest
2 голосов
/ 24 декабря 2009

Я создаю приложение MVC 2 и использую linq to sql с сохраненными процессами.

Я создал слой доступа к данным, который имеет внутренний класс datacontext и открытый класс, который я предоставляю приложениям. В моем общедоступном классе я предоставляю методы, которые обращаются к классу datacontext и преобразуют данные в мои собственные классы объектной модели, используя linq.

В моем общедоступном классе я бы выставил метод, используя следующий шаблон:

public IEnumerable<MyObject> ListObjects(int iParameter)
{
    using (MyDataContext db = new MyDataContext)
    {
        //call stored proc and convert results to my object model
        return db.List_Objects().Select(o => new MyObject()
            {
                ID = o.ID,
                Name = o.Name
                Text = o.Code + " " + o.Description
            };
    } 
} 

Мое приложение MVC будет вызывать этот метод из модельного класса, а aspx будет перебирать результаты. Я обнаружил, что всегда получаю сообщение об ошибке «datacontext вызывает недопустимую попытку вызова Read, когда читатель закрыт», потому что я оборачиваю использование контекста данных в область использования. Если я не определяю все в предложении использования, он работает нормально. Почему это?

Я думаю это не обязательно вещь linq или mvc (но не знаю наверняка), вызывает ли использование утверждение, вызывающее dispose, прежде чем все объекты будут возвращены? Или, может быть, предложение select выполняется только во время итерации перечислителя, аналогично тому, как работает yield?

Ответы [ 2 ]

3 голосов
/ 24 декабря 2009

Linq to Sql использует шаблон единицы работы для инкапсуляции доступа к базе данных, которая при удалении (конец использования области действия) закрывает соединение с базой данных, причина, по которой он работает, когда вы не переносите оператор, - контекст еще жив при перечислении запроса (который может быть плохим, поскольку это может привести к тому, что соединение остается открытым), он выбрасывает, потому что выполнение будет происходить только тогда, когда вы впервые используете IEnumerable, который может быть где-то вниз по линии до представления. вам нужно преобразовать IEnumerable в список, используя ToList(), который немедленно запустит выполнение, а не откладывает его, поэтому соединение закроется, и вы получите свою коллекцию.

1 голос
/ 24 декабря 2009

Использование продолжается для вызова метода, поэтому, если у вас есть это:

var objects = ListObjects(123);

Затем DataContext был создан и удален, но результаты пока не возвращены.

Когда вы начинаете перечислять результаты:

foreach(var o in objects)

Дерево выражений метода начинает выполнять запрос, но текст данных уже расположен и, следовательно, не может открыть новое соединение.

Нечто подобное будет работать, но не позволяет «расширять» запрос извне объектов ListObjects.

public IEnumerable<MyObject> ListObjects(int iParameter)
{
    List<MyObject> objects;
    using (MyDataContext db = new MyDataContext())
    {
        //call stored proc and convert results to my object model
        objects = (db.List_Objects().Select(o => new MyObject()
            {
                ID = o.ID,
                Name = o.Name
                Text = o.Code + " " + o.Description
            }).ToList();
    } 
    return objects;
}

Если вы понимаете, когда распоряжаться контекстом, а когда нет, то это безопасно, ИМО.

...