When should I use IEnumerable and when IQueryable?

0

Issue

I have tried to look for a difference quite a few times and there are multiple answers.

One of the common known difference is that IEnumerable filters data from within memory while IQueryable does it on the server side.

What does this mean exactly?

Isn’t filtering occurring on in-memory data still a server side thing?

I have tried to look for their use in multiple places but I haven’t been able to find it in simple words.

Thank you.

Solution

IEnumerable<T> represents something which produces a sequence of results. However, it doesn’t expose any information about how the sequence is produced.

IQueryable<T> exposes the information about how the sequence is to be produced, at the Expression property, in the form of an expression tree. This information can then be easily mapped to a different set of instructions.

If you call Enumerable.Where on an IEnumerable<T>, you’re passing in a compiled method compatible with Func<T, bool>. In theory, we could parse the IL of the compiled method to figure out what the method does, and use that to map to another set of instructions; but that’s very complex. Inevitably, the only way to work with this is to load all the objects into memory from the server/provider/datasource, and apply the compiled method on each object.

If you call Queryable.Where on an IQueryable<T>, you’re passing in an object which by definition represents different code operations — Expression<Func<T, bool>>. For example:

IQueryable<Person> qry = /* ... */;
qry = qry.Where(x => x.LastName.StartsWith("A"));

the compiler converts x => x.LastName.StartsWith("A") to an object representing its various parts:

Lambda expression, returning a `bool`
    with an `x` parameter of type `Person`
    Call the `StartsWith` method, passing in a constant string `"A"`, on
        Result of the `LastName` property, of
            the `x` element

More, calling Queryable.Where itself also modifies the underlying expression tree:

Call to Queryable.Where, passing in
    The object at `qry`, and
    The previous lambda expression (see above)

When the query is enumerated (either with a foreach, or a call to ToList, or something similar), the information can easily be mapped from this object into another form, such as SQL:

SELECT *
FROM Persons
WHERE LastName LIKE N'A%'

or a web request:

http://example.com/Person?lastname[0]=a

The final expression tree after calling Queryable.Where will look something like this object graph, if it were possible to construct expression trees using constructors and object and collection initializers:

var x = new ParameterExpression {
    Type = typeof(Person),
    Name = "x"
};

new MethodCallExpression {
    Type = typeof(IQueryable<Person>),
    Arguments = new ReadOnlyCollection<Expression> {
        new ConstantExpression {
            Type = typeof(EnumerableQuery<Person>)
        },
        new UnaryExpression {
            NodeType = ExpressionType.Quote,
            Type = typeof(Expression<Func<Person, bool>>),
            Operand = new Expression<Func<Person, bool>> {
                NodeType = ExpressionType.Lambda,
                Type = typeof(Func<Person, bool>),
                Parameters = new ReadOnlyCollection<ParameterExpression> {
                    x
                },
                Body = new MethodCallExpression {
                    Type = typeof(bool),
                    Object = new MemberExpression {
                        Type = typeof(string),
                        Expression = x,
                        Member = typeof(Person).GetProperty("LastName")
                    },
                    Arguments = new ReadOnlyCollection<Expression> {
                        new ConstantExpression {
                            Type = typeof(string),
                            Value = "A"
                        }
                    },
                    Method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) })
                },
                ReturnType = typeof(bool)
            }
        }
    },
    Method = typeof(Queryable).GetMethod("Where", new[] { typeof(IQueryable<Person>), typeof(Expression<Func<Person, bool>>) })
}

(NB. This was written using the ExpressionTreeToString library. Disclaimer: I am the author.)

Answered By – Zev Spitz

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave A Reply

Your email address will not be published.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More