This project is read-only.
1

Resolved

LINQ query called for each reference

description

While working on the grade/graduation date issue, I discovered that the CheckInWizard was calling the Controller's CanCheckIn method multiple times. Jason and I tracked this down and are replacing the "var pplToCheckIn" with "List<FamilyMember> pplToCheckIn" and calling ToList() on the query.
 
This is fixed in CheckInWizard.ascx.cs Revision: 40.

comments

JasonOffutt wrote Sep 1, 2009 at 10:57 PM

The Linq in question was in the ShowSelectFamilyMember() method of the CheckInWizard.ascx.cs file. Here's a snippet:

var pplToCheckIn = from FamilyMember fm in familyMembers
                         where Controller.CanCheckIn(fm, int.Parse(MaximumAgeSetting), int.Parse(MaximumGradeSetting))
                         select fm;
The problem we experienced was due to this bit of Linq having no true lexical closure. Here's a pretty good article explaining the concept:
http://blogs.msdn.com/abhinaba/archive/2005/10/18/482180.aspx

The result (unintentional) was causing the CheckinBLL's Controller.CanCheckIn() method to fire 5 separate times, when it really only needed to be run once. It was firing EVERY time we referenced that 'pplToCheckIn' collection object. Since there's no true lexical closure (no permanent in-memory object) in this scenario, the collection must be rebuilt every time it's referenced.

Our fix was very simplistic:

List<FamilyMember> pplToCheckIn = (from FamilyMember fm in familyMembers
                                                    where Controller.CanCheckIn(fm, int.Parse(MaximumAgeSetting), int.Parse(MaximumGradeSetting))
                                                    select fm).ToList();
Why does this create a lexical closure and not the first? A Linq query will always return an IEnumerable. Unless we cast it to an object that DOES have a constructor, .NET will re-run the Linq query every time the reference is used in code. IEnumerable has no constructor, it's an interface. So now that we have a concrete object, we cut a LOT of inefficiency out of our code.

Going into this project, I really didn't fully understand how that all worked. So, in many places, I built it with false assumptions of how Linq works. As we review our code for the next release, we'll keep an eye out for this issue in other places.

wrote Feb 1, 2013 at 4:23 AM

wrote May 14, 2013 at 2:43 AM

wrote May 14, 2013 at 2:43 AM

wrote Jun 12, 2013 at 1:10 AM