Подтвердить что ты не робот

Операция не может быть выполнена, так как DbContext был удален

Я новичок в EF, и я пытаюсь использовать метод расширения, который преобразует из моего типа базы данных User в мой информационный класс UserInfo.
Я использую базу данных сначала, если это имеет значение?

Мой код ниже дает ошибку

Операция не может быть завершена, так как был удален DbContext.

try
{
    IQueryable<User> users;
    using (var dataContext = new dataContext())
    {
        users = dataContext.Users
                  .Where(x => x.AccountID == accountId && x.IsAdmin == false);
        if(users.Any() == false)
        {
            return null;
        }
    }
    return users.Select(x => x.ToInfo()).ToList(); // this line is the problem
}
catch (Exception ex)
{
    //...
}

Я могу понять, почему он это сделает, но я также не понимаю, почему результат инструкции where не сохраняется в объекте users?

Итак, я думаю, мой главный вопрос: почему он не работает, а во-вторых, какой правильный способ использования методов расширения и EF?

4b9b3361

Ответ 1

Этот вопрос дал мне понять, что IQueryable требует активного контекста для его работы. Это означает, что вы должны попробовать это:

try
{
    IQueryable<User> users;

    using (var dataContext = new dataContext())
    {
        users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

        if(users.Any() == false)
        {
            return null;
        }
        else
        {
            return users.Select(x => x.ToInfo()).ToList(); // this line is the problem
        }
    }


}
catch (Exception ex)
{
    ...
}

Ответ 2

Объекты, выставленные как IQueryable<T> и IEnumerable<T>, фактически не выполняются до тех пор, пока они не будут повторены или иным образом недоступны, например, составлены в List<T>. Когда EF возвращает IQueryable<T>, он по существу просто компонует что-то, способное извлекать данные, оно фактически не выполняет извлечение, пока вы его не уничтожаете.

Вы можете почувствовать это, поставив точку останова, где определена IQueryable, и когда вызывается .ToList(). (Изнутри контекста данных, как правильно указал Jofry.) Работа по извлечению данных выполняется во время вызова ToList().

Из-за этого вам нужно сохранить IQueryable<T> в рамках контекста данных.

Ответ 3

Вы должны помнить, что запросы IQueryable фактически не выполняются в хранилище данных, пока вы не перечислите их.

using (var dataContext = new dataContext())
{

Эта строка кода фактически не делает ничего, кроме создания инструкции SQL

    users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

.Any() - это операция, которая перечисляет IQueryable, поэтому SQL отправляется в источник данных (через dataContext), а затем выполняется действие .Any() против него

    if(users.Any() == false)
    {
        return null;
    }
}

Ваша строка "проблема" повторно использует построенный выше sql, а затем выполняет дополнительную операцию (.Select()), которая просто добавляет к запросу. Если вы оставили его здесь, никаких исключений, кроме вашей проблемной строки

return users.Select(x => x.ToInfo()).ToList(); // this line is the problem

вызывает .ToList(), который перечисляет IQueryable, который вызывает отправку SQL в источник данных через dataContext, который использовался в исходном запросе LINQ. Поскольку этот dataContext был удален, он уже недействителен, а .ToList() выдает исключение.

Вот почему это не работает. Исправление состоит в том, чтобы переместить эту строку кода в область вашего информационного объекта.

Как правильно использовать его - это еще один вопрос с несколькими, возможно, правильными ответами, которые зависят от вашего приложения (Forms vs. ASP.net и MVC и т.д.). Образцом, который это реализует, является шаблон Единицы работы. Для создания нового объекта контекста практически нет затрат, поэтому общее правило состоит в том, чтобы создать его, выполнить свою работу и затем избавиться от него. В веб-приложениях некоторые люди создадут контекст для каждого запроса.

Ответ 4

Причина, по которой она выбрасывает ошибку, - это объект, и после этого мы пытаемся получить доступ к значениям таблиц через объект, но объект удален. Позвольте преобразовать это в ToList(), чтобы мы могли иметь значения

Возможно, он фактически не получает данные, пока вы его не используете (это ленивая загрузка), поэтому dataContext не существует, когда вы пытаетесь выполнить эту работу. Бьюсь об заклад, если бы вы сделали ToList() в области, это было бы нормально.

try
{
    IQueryable<User> users;
    var ret = null;

    using (var dataContext = new dataContext())
    {
        users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

        if(users.Any())
        {
            ret = users.Select(x => x.ToInfo()).ToList(); 
        }

     }

   Return ret;
}
catch (Exception ex)
{
    ...
}

Ответ 5

Это может быть так же просто, как добавить ToList() в ваш репозиторий. Например:

public IEnumerable<MyObject> GetMyObjectsForId(string id)
{
    using (var ctxt = new RcContext())
    {
        // causes an error
        return ctxt.MyObjects.Where(x => x.MyObjects.Id == id);
    }
}

Уступит Db Context, расположенную в вызывающем классе, но это может быть разрешено путем явного осуществления перечисления путем добавления ToList() в операцию LINQ:

public IEnumerable<MyObject> GetMyObjectsForId(string id)
{
    using (var ctxt = new RcContext())
    {
        return ctxt.MyObjects.Where(x => x.MyObjects.Id == id).ToList();
    }
}

Ответ 6

Измените это:

using (var dataContext = new dataContext())
{
    users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

    if(users.Any())
    {
        ret = users.Select(x => x.ToInfo()).ToList(); 
    }

 }

:

using (var dataContext = new dataContext())
{
    return = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false).Select(x => x.ToInfo()).ToList();
} 

Суть в том, что вы только хотите принудительно перечислить набор данных контекста один раз. Пусть вызывающий абонент имеет дело с пустым сценарием, как и должно быть.

Ответ 7

Здесь вы пытаетесь выполнить объект IQueryable в неактивном DBContext. ваш DBcontext уже удален. вы можете выполнить только объект IQueryable до удаления DBContext. Значит, вам нужно написать инструкцию users.Select(x => x.ToInfo()).ToList() внутри с помощью области

Ответ 9

using(var database=new DatabaseEntities()){}

Не используйте оператор использования. Просто пиши так

DatabaseEntities database=new DatabaseEntities ();{}

Это будет работать.

Для документации по using смотрите здесь.