LINQ Lazy Loading and PreFetch

March 17, 2010

Today, during unit testing, the application I’m working on threw an exception:

Cannot access a disposed object. Object name: ‘DataContext accessed after Dispose.’

This occured whilst accessing the property of a LINQ dataset returned from a method. My initial thoughts were:

“‘Whats the concern about the DataContext being disposed? I know its disposed, because thats what my code does, but my method has returned the data, now I just want to use it!”

Well, it turns out the error was due to a behaviour of LINQ commonly known as ‘Lazy Loading’. This effectivley means that related data is not automatically loaded. Kind of makes sense – After all, if we request a company or collection of company objects from our DataContext, we don’t always want to get the related Employee records, Customers etc (not to mention the orders that belong to the customers, holiday records that belong to the Employees…and so on!!)

So – Loading of related objects (records) is optional – In order to access one of them Employee records for the company you’ve retrieved, you’ll need to ask for the data in the first place – Commonly known as a ‘PreFetch’ option.

Following code would cause a ‘disposed object’ exception when we try to access Company.Employee, because the employee records will not be loaded:


using (MyDataContext MyDB = new MyDataContext(ConfigurationManager.ConnectionStrings["MyConnectionString"].ToString()))
{
company = (from c in MyDB.Company where c.ID == CompanyID select c).FirstOrDefault();
}

Here we have the same code, with Companies Employee records pre-fetched, allowing us to access Company.Employees collection


using (MyDataContext MyDB = new MyDataContext(ConfigurationManager.ConnectionStrings["MyConnectionString"].ToString()))
{
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Company>(c => c.Employees);
MyDB.LoadOptions = loadOptions;
company = (from c in MyDB.Company where c.ID == CompanyID select c).FirstOrDefault();
}

If you want to pre-fetch more than one set of related data, simply add a line for each related object collection:


...
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Company>(c => c.Employees);
loadOptions.LoadWith<Company>(c => c.Buildings);
loadOptions.LoadWith<Company>(c => c.Vehicles);
MyDB.LoadOptions = loadOptions;
...

Note that within Visual Studio from the LINQ2SQL Surface designer, its possible to set the ‘Delay Loaded’ property of any object property. This is false by default, meaning we always get the data for all properties when loading an object or collection of objects. I’ve not had a need to set this yet myself, but this could be hand when working with BLOB/Binary data types for storing photos for example, which you may not always be making use of.

Advertisements

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

%d bloggers like this: