Различия при использовании IEnumerable и IQueryable в качестве типа ObjectSet
как я понимаю, когда я использую методы расширения LINQ (с синтаксисом лямбда-выражения) на IQueryable
это на самом деле экземпляр ObjectSet
они переводятся в запросы LINQ to SQL. Я имею в виду эту команду
IQueryable<User> users = db.UserSet;
var users32YearsOld = users.Where(user => user.Age == 32);
точно так же, как
IQueryable<User> users = db.UserSet;
var users32YearsOld = from user in users where user.Age == 32 select user;
поэтому non из них попадает в базу данных, пока они users32YearsOld
перечислены в течение цикла или. (Надеюсь я правильно понимаю).
но что произойдет, если я не маска ObjectSet
as IQueryable
, а как IEnumerable
? Поэтому, если тип его IEnumerable
?
IEnumerable<User> users = db.UserSet;
var users32YearsOld = users.Where(user => user.Age == 32);
он сразу попал в базу данных (если да то когда ? Прямо на первой строке или на второй) ? Или он будет вести себя как предыдущая команда, которая не попадет в базу данных до users32YearsOld
перечисляется ? Будет ли какая-то разница, если вместо этого я буду использовать following ?
IEnumerable<User> users = db.UserSet;
var users32YearsOld = from user in users where user.Age == 32 select user;
спасибо
3 ответов
Undeleting мой ответ, потому что я только что протестировал его, и он работает точно так, как я описал:
ни один из упомянутых запросов попадет в базу данных, потому что не было перечисления. Разница между IQueryable
запрос и IEnumerable
запрос-это в случае IQueryable
фильтрация будет выполняться на сервере базы данных, а в случае IEnumerable
все объекты будут загружены из базы данных в память, а фильтрация будет выполнена в коде .NET (linq-to-objects). Как вы можете себе представить, это обычно убийца производительности.
я написал простой тест в моем проекте:
[TestMethod]
public void Test()
{
// ObjectQuery<Department> converted ot IEnumerable<Department>
IEnumerable<Department> departmetns = CreateUnitOfWork().GetRepository<Department>().GetQuery();
// No query execution here - Enumerable has also deffered exection
var query = departmetns.Where(d => d.Id == 1);
// Queries ALL DEPARTMENTS here and executes First on the retrieved result set
var result = departmetns.First();
}
вот простое объяснение:
IEnumerable<User> usersEnumerable = db.UserSet;
IQueryable<User> usersQueryable = db.UserSet;
var users = /* one of usersEnumerable or usersQueryable */;
var age32StartsWithG = users.Where(user => user.Age == 32)
.Where(user => user.Name.StartsWith("G");
если вы используете usersEnumerable
, когда вы начинаете перечислять за него два Where
s будет выполняться последовательно; сначала ObjectSet
будет получать все объекты, и объекты будут отфильтрованы до 32 лет, а затем они будут отфильтрованы до тех, чье имя начинается с G.
если вы используете usersQueryable
, два Where
s вернет новые объекты, которые будут накапливать критерии выбора, и когда вы начнете перечисляя его, он преобразует все критерии в запрос. Это делает заметную разницу.
обычно вам не нужно беспокоиться, так как вы либо скажете var users
или ObjectSet users
когда вы объявляете свою переменную, это означает, что C# будет знать, что вы заинтересованы в вызове наиболее конкретного метода, доступного на ObjectSet
и IQueryable
запрос оператор методы (Where
, Select
, ...) являются более конкретными, чем IEnumerable
методы. Однако, если вы пройдете вокруг объектов к методам, которые принимают IEnumerable
параметры, они могут в конечном итоге вызвать неправильные методы.
вы также можете использовать способ, которым это работает в вашу пользу с помощью AsEnumerable()
и AsQueryable()
методы, чтобы начать использовать другой подход. Например, var groupedPeople = users.Where(user => user.Age > 15).AsEnumerable().GroupBy(user => user.Age);
вытащит правильных пользователей с запросом базы данных, а затем сгруппирует объекты локально.
как уже говорили другие, Стоит повторить, что ничего не происходит, пока вы не начнете перечислять последовательности (с foreach
). Теперь вы должны понять, почему это не может быть иначе: если все результаты были получены сразу, вы не можете создавать запросы для перевода в более эффективный запрос (например, SQL-запрос).
вы правы насчет IQueryable. Что касается IEnumerable, он сразу же попадет в базу данных при назначении пользователя IEnumerable.
нет никакой реальной разницы между использованием расширений Linq и синтаксиса в приведенном примере. Иногда то или другое будет удобнее (см. linq-extension-methods-vs-linq-синтаксис), но ИМО это больше о личных предпочтений.