Различия при использовании 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, когда вы начинаете перечислять за него два Wheres будет выполняться последовательно; сначала ObjectSet будет получать все объекты, и объекты будут отфильтрованы до 32 лет, а затем они будут отфильтрованы до тех, чье имя начинается с G.

если вы используете usersQueryable, два Wheres вернет новые объекты, которые будут накапливать критерии выбора, и когда вы начнете перечисляя его, он преобразует все критерии в запрос. Это делает заметную разницу.

обычно вам не нужно беспокоиться, так как вы либо скажете 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-синтаксис), но ИМО это больше о личных предпочтений.