Вы должны знать об отложенном выполнении, которое использует LINQ.
Предполагая, что db.Custs
- это объект, реализующий IQueryable<Cust>
или что-то подобное.
Если вы проверите введите a
в первом примере, вы увидите, что это IQueryable<Cust>
. Во втором примере - это Cust
.
Если вы изучите методы LINQ, вы заметите, что есть две их группы: те, которые возвращают IEnumerable<TResult>
(или IQueryable<TResult>
). и те, которые этого не делают.
Select, Join, GroupBy являются примерами первой группы .. не выполняйте запрос. Они не представляют собой извлеченные данные, они представляют собой возможность выбора данных и их перечисления. Пока вы объединяете функции из этой группы. источник ваших данных не запрашивается. Нередко база данных, но это может быть что угодно, перечислимое, читалка CSV-файлов, JSON -файлы, информация из целого rnet. В терминах LINQ говорится, что они используют отложенное выполнение. Вы можете найти этот термин в каждом описании метода.
Примеры методов из второй группы: ToList, FirstOrDefault, Count, Any: возвращается не IQueryable<...>
. При выполнении одного из этих методов начнется перечисление IEnumerable / IQueryable, который является источником ввода: будет выбран первый элемент, и если он есть, и если это необходимо для метода, будут получены другие элементы последовательности.
Вернуться к вашему вопросу
Ваша первая загрузка страницы создаст запрос. Создан потенциал для получения данных из вашей базы данных. Увы, вы забыли выполнить запрос. Если вы отлаживаете свою программу и останавливаете все потоки в точке останова и хотите проверить значение a, вы хотите увидеть свойства объекта a
. Увы, ваш отладчик готов показать вам результаты простых свойств, но связаться с базой данных для него слишком сложно.
Следовательно, если вы действительно хотите увидеть результат запроса к базе данных во время отладки, вы Придется выполнить запрос, добавив метод второй группы. Чаще всего временно добавляют ToList()
.
Во втором примере вы использовали метод из второй группы: запрос был выполнен, а результат был помещен в локальную память: отладчик может получить доступ к данным, потому что ему нужно только проверить некоторую память.
Итак, для отладки решение просто: добавьте ToList
перед исследованием.
Улучшения
К настоящему времени вы знаете, что переменная a
в первом примере выражает возможность получения данных, а не сами полученные данные. Вы, очевидно, упростили свой код для вопроса, вы хотите что-то сделать с данными.
- Я почти уверен, что SSEntities реализует
IDisposable
. Вы должны удалить его, как только он вам больше не нужен. - Убедитесь, что вы извлекаете данные (выполняете запрос), прежде чем удалять SSEntities.
Обычно люди используют следующая структура, чтобы убедиться, что объект размещен должным образом при любых обстоятельствах:
using (SSEntities db = new SSEntities())
{
var myQuery = db.Custs.Select(cust => new {...});
// execute the query:
var fetchedData = myQuery.ToList();
}
Обратите внимание на следующую ловушку:
IQueryable<Cust> GetCustomers()
{
using (SSEntities db = new SSEntities())
{
return db.Custs.Select(cust => new {...});
}
}
Запрос не выполняется, но вы ' удалил SSEntities. Ваш компилятор не будет жаловаться, вы получите исключение во время выполнения.
Правильное решение - позволить вызывающему абоненту создавать и удалять соединение с базой данных, вы предоставляете только выбор:
static IQueryable<Cust> GetCustomersByPostCode(this IQueryable<Cust> customers,
PostCode postCode)
{
return customers.Where(customer => customer.PostCode == postCode)
.Select(customer => new {...});
}
Использование:
protected void Page_Load(object sender, EventArgs e)
{
List<Customer> customers = null;
using (SSEntities db = new SSEntities())
{
PostCode postCode = ...
customers = db.Customers.GetCustomersByPostCode(postCode).ToList();
}
// the database is disposed, cannot be used anymore
// customers already fetched, can still be used:
ProcessFetchedCustomers(customers);
}