Returning IEnumerable vs. IQueryable

前端 未结 14 2494
梦毁少年i
梦毁少年i 2020-11-21 22:59

What is the difference between returning IQueryable vs. IEnumerable, when should one be preferred over the other?



        
相关标签:
14条回答
  • 2020-11-21 23:46

    In addition to the above, it's interesting to note that you can get exceptions if you use IQueryable instead of IEnumerable:

    The following works fine if products is an IEnumerable:

    products.Skip(-4);
    

    However if products is an IQueryable and it's trying to access records from a DB table, then you'll get this error:

    The offset specified in a OFFSET clause may not be negative.

    This is because the following query was constructed:

    SELECT [p].[ProductId]
    FROM [Products] AS [p]
    ORDER BY (SELECT 1)
    OFFSET @__p_0 ROWS
    

    and OFFSET can't have a negative value.

    0 讨论(0)
  • 2020-11-21 23:47

    We can use both for the same way, and they are only different in the performance.

    IQueryable only executes against the database in an efficient way. It means that it creates an entire select query and only gets the related records.

    For example, we want to take the top 10 customers whose name start with ‘Nimal’. In this case the select query will be generated as select top 10 * from Customer where name like ‘Nimal%’.

    But if we used IEnumerable, the query would be like select * from Customer where name like ‘Nimal%’ and the top ten will be filtered at the C# coding level (it gets all the customer records from the database and passes them into C#).

    0 讨论(0)
  • 2020-11-21 23:57

    In addition to first 2 really good answers (by driis & by Jacob) :

    IEnumerable interface is in the System.Collections namespace.

    The IEnumerable object represents a set of data in memory and can move on this data only forward. The query represented by the IEnumerable object is executed immediately and completely, so the application receives data quickly.

    When the query is executed, IEnumerable loads all the data, and if we need to filter it, the filtering itself is done on the client side.

    IQueryable interface is located in the System.Linq namespace.

    The IQueryable object provides remote access to the database and allows you to navigate through the data either in a direct order from beginning to end, or in the reverse order. In the process of creating a query, the returned object is IQueryable, the query is optimized. As a result, less memory is consumed during its execution, less network bandwidth, but at the same time it can be processed slightly more slowly than a query that returns an IEnumerable object.

    What to choose?

    If you need the entire set of returned data, then it's better to use IEnumerable, which provides the maximum speed.

    If you DO NOT need the entire set of returned data, but only some filtered data, then it's better to use IQueryable.

    0 讨论(0)
  • 2020-11-21 23:59

    Yes, both will give you deferred execution.

    The difference is that IQueryable<T> is the interface that allows LINQ-to-SQL (LINQ.-to-anything really) to work. So if you further refine your query on an IQueryable<T>, that query will be executed in the database, if possible.

    For the IEnumerable<T> case, it will be LINQ-to-object, meaning that all objects matching the original query will have to be loaded into memory from the database.

    In code:

    IQueryable<Customer> custs = ...;
    // Later on...
    var goldCustomers = custs.Where(c => c.IsGold);
    

    That code will execute SQL to only select gold customers. The following code, on the other hand, will execute the original query in the database, then filtering out the non-gold customers in the memory:

    IEnumerable<Customer> custs = ...;
    // Later on...
    var goldCustomers = custs.Where(c => c.IsGold);
    

    This is quite an important difference, and working on IQueryable<T> can in many cases save you from returning too many rows from the database. Another prime example is doing paging: If you use Take and Skip on IQueryable, you will only get the number of rows requested; doing that on an IEnumerable<T> will cause all of your rows to be loaded in memory.

    0 讨论(0)
  • 2020-11-21 23:59

    There is a blog post with brief source code sample about how misuse of IEnumerable<T> can dramatically impact LINQ query performance: Entity Framework: IQueryable vs. IEnumerable.

    If we dig deeper and look into the sources, we can see that there are obviously different extension methods are perfomed for IEnumerable<T>:

    // Type: System.Linq.Enumerable
    // Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    // Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll
    public static class Enumerable
    {
        public static IEnumerable<TSource> Where<TSource>(
            this IEnumerable<TSource> source, 
            Func<TSource, bool> predicate)
        {
            return (IEnumerable<TSource>) 
                new Enumerable.WhereEnumerableIterator<TSource>(source, predicate);
        }
    }
    

    and IQueryable<T>:

    // Type: System.Linq.Queryable
    // Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    // Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll
    public static class Queryable
    {
        public static IQueryable<TSource> Where<TSource>(
            this IQueryable<TSource> source, 
            Expression<Func<TSource, bool>> predicate)
        {
            return source.Provider.CreateQuery<TSource>(
                Expression.Call(
                    null, 
                    ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(
                        new Type[] { typeof(TSource) }), 
                        new Expression[] 
                            { source.Expression, Expression.Quote(predicate) }));
        }
    }
    

    The first one returns enumerable iterator, and the second one creates query through the query provider, specified in IQueryable source.

    0 讨论(0)
  • 2020-11-22 00:01

    The main difference between “IEnumerable” and “IQueryable” is about where the filter logic is executed. One executes on the client side (in memory) and the other executes on the database.

    For example, we can consider an example where we have 10,000 records for a user in our database and let's say only 900 out which are active users, so in this case if we use “IEnumerable” then first it loads all 10,000 records in memory and then applies the IsActive filter on it which eventually returns the 900 active users.

    While on the other hand on the same case if we use “IQueryable” it will directly apply the IsActive filter on the database which directly from there will return the 900 active users.

    0 讨论(0)
提交回复
热议问题