views:

99

answers:

3

Assume we have a method like this:

public IEnumerable<T> FirstMethod()
{
    var entities = from t in context.Products
                   where {some conditions}
                   select t;

    foreach( var entity in entities )
    {
        entity.SomeProperty = {SomeValue};
        yield return entity;   
    }
}

where context is a DataContext that is generated by Linq to SQL designer.

Does "FirstMethod" load the data into memory from database (because of the foreach loop) or will it still defer-load it until another foreach loop that doesn't have "yield return" is found in another method like the following?

public void SecondMethod()
{
    foreach( var item in FirstMethod() )
    {
        {Do Something}
    }
}
+6  A: 

The latter (deferred); FirstMethod is an iterator block (because of yield return); this means that you have a chain of iterators. Nothing is read until the final caller starts iterating the data; then each record is read in turn during the final caller's foreach (between which the connection/command is open).

The using that surrounds foreach (under the bonnet) ensures that the connection is closed if the foreach is abandoned half-way-through.

If you want to load the data earlier, use .ToList() or .ToArray() to buffer the data locally - but note that this breaks "composition" - i.e. the caller can no longer add extra Where etc clauses (which they can if it returns a raw IQueryable<T>).


Re your question:

public IEnumerable<T> FirstMethod()
{
    var entities = from t in context.Products
                   where {some conditions}
                   select t;

    foreach( var entity in entities.AsEnumerable() )
    {
        entity.SomeProperty = {SomeValue};
        yield return entity;   
    }
}

The AsEnumerable is the key here; it ends the composable IQueryable<T> chain, and uses LINQ-to-Objects for the rest.

Marc Gravell
You learn something new every day, I guess. I'll delete my answer :P
Alex Fort
I've checked the data context log and it seems that other linq clauses will not translate to SQL commands. Is there any way to this? All I want is to set a property (that is not a column) when the result set returns from an IQueryable<T> method.
Mohammadreza
Yes - I'll update
Marc Gravell
+1  A: 

Loading is deferred until the GetEnumerator method is called on the entities query and that won't happen until the GetEnumerator method is called on the IEnumerable<T> you're returning.

Vojislav Stojkovic
+2  A: 

In short, it doesn't load until SecondMethod performs the iteration...

Read here for more...

Jason Punyon