Поскольку этот поток немного разветвился в общем обсуждении текущих реализаций с плавающей запятой, я бы добавил, что есть проекты по исправлению их проблем.
Взгляните на https: // posithub.org/, который демонстрирует тип номера, называемый posit (и его предшественник unum), который обещает предложить лучшую точность с меньшим количеством бит. Если мое понимание верное, оно также фиксирует проблемы в вопросе. Весьма интересный проект, человек, стоящий за ним, является математиком Dr. Джон Густафсон . Все это с открытым исходным кодом, с множеством реализаций в C / C ++, Python, Julia и C # ( https://hastlayer.com/arithmetics ).
Причина, по которой она выбрасывает ошибку, - это объект, и после этого мы пытаемся получить доступ к значениям таблиц через объект, но объект удален. Позвольте преобразовать это в 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)
{
...
}
Измените это:
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();
}
Суть в том, что вы только хотите принудительно перечислить набор данных контекста один раз. Пусть вызывающий абонент имеет дело с пустым сценарием, как и должно быть.
Это может быть так же просто, как добавить 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();
}
}
Вы должны помнить, что запросы 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 () выдает исключение.
Это «почему он не работает». Исправление состоит в том, чтобы переместить эту строку кода в область вашего объекта dataContext.
Как правильно использовать его - это еще один вопрос с несколькими, возможно, правильными ответами, которые зависят от вашего приложения (Forms vs. ASP.net vs MVC и т. Д.). Образцом, который это реализует, является шаблон Единицы работы. Для создания нового объекта контекста практически нет затрат, поэтому общее правило состоит в том, чтобы создать его, выполнить свою работу и затем избавиться от него. В веб-приложениях некоторые люди создадут контекст для каждого запроса.
Здесь вы пытаетесь выполнить объект IQueryable в неактивном DBContext. ваш DBcontext уже удален. вы можете выполнить только объект IQueryable до удаления DBContext. Значит, вам нужно написать инструкцию users.Select(x => x.ToInfo()).ToList()
внутри с помощью области
Объекты, выставленные как IQueryable<T>
и IEnumerable<T>
, фактически не выполняются до тех пор, пока они не будут повторены или иным образом недоступны, например, составлены в List<T>
. Когда EF возвращает IQueryable<T>
, он по существу просто создает что-то, способное извлекать данные, оно фактически не выполняет извлечение, пока вы его не уничтожаете.
Вы можете почувствовать это, поставив точку останова, где IQueryable
определяется, когда вызывается .ToList()
. (Изнутри контекста данных, как правильно указал Jofry.) Работа по извлечению данных выполняется во время вызова ToList()
.
Из-за этого вам нужно сохранить IQueryable<T>
в рамках контекста данных.