Hacking Linq for Set Based Eager Loading with Entities

First I will show the result:

var series = Series.GetAllSeries(em).ToList();
series.Select(s => { s.SeriesGenres.Load(); return true; }).ToList();
series.Select(s => { s.SeriesGenres.Select(sg => { 
     sg.GenreReference.Load(); return true; }
).ToList(); return true; }).ToList();

So what is going on here, and why am I doing this.  So first the reason I am doing this is that I am trying to maintain my context within the controller and not persisting it to my View.  However, in this case we are dealing with a set of Series as opposed to a single Series.  In this case we want to load all related types without resorting to foreach statements, as that is what Linq is here to help us circumvent.  Now to what this is doing.

The first line is pretty obvious, it makes a call into our Series model and returns an IEnumerable which we force enumeration on by calling .ToList(). 

Moving to the second line, understand that our goal now becomes to Load the SeriesGenre collection of each Series in the set.  This is what Select is for, to allow operation on individual instances within a set.  Normally, Select returns an IEnumerable where T is the inferred type of the property being returned.  So this code effectively says: “For each Series as s in series call s.SeriesGenres.Load()”.  However, since Load returns void and Select inferred type for T cannot be void (IEnumerable would not be especially useful) we have to return an explicit type that it can infer.  C# Lambda’s do allow for statements within { }, thus we can return true for the operation.

An important point here, this expression will NOT be loaded without calling .ToList() at the end. Why? Because, aside from Linq to Objects, Linq statements delay enumeration until you call them.  However, since we need this to be loaded immediately, in preparation for the next Linq query, we force enumeration by calling .ToList(), thus this  yields a List, which we do not assign.  One can think of a call to ToList() effectively changing context from Linq to Entities to Linq to Objects.

Moving to the final query:

series.Select(s => { s.SeriesGenres.Select(sg => { 
     sg.GenreReference.Load(); return true; }
).ToList(); return true; }).ToList();

We can really see a lot of the same practices being used here as above, except this is multi-level.  Again notice the use of .ToList() to force the set enumeration at each level and the use of multi-statement lambda’s to explicitly specify the return type of Select.

So the main point of this blurb is to show the trouble one has to go through to utilize Loaded reference types in the Entity framework in a set based fashion.  Microsoft’s recommended practice regarding the Entity Framework seems to be to simply keep the context open for the duration of each life cycle.  Thankfully, they are promising that lazy loading will be more automated in the next release.

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s