LINQ to SQL – DataContext Load Options

The LINQ framework provide a simple (although not a mature) solution to eager loading data, namely the DataLoadOptions class. This class allows you to specify what related data should be retrieved when some data X is retrieved, for example you can tell the data context to load all related apartments when loading a building:

DataLoadOptions options = new System.Data.Linq.DataLoadOptions();
options.LoadWith<Building>(building => building.Apartments);
_DataContext = new RdmDataContext();
_DataContext.LoadOptions = options;

This is great, whenever you request a building LINQ will automatically retrieve all the related apartments, there are some negatives to this though, so you need to think through your load options carefully.

Using the data load options above, if you request a list of buildings off the data context LINQ will hit the database just once to retrieve all the buildings and apartments so you will get the duplicate building information retrived for each apartment. Now this doesn’t affect your LINQ entities but it does mean you are retrieving more data than is needed. It would be nice if the guys at Microsoft could change the eager loading to first retrieve all the buildings and then a seperate query to retrieve all the related apartments.

You can’t request eager loading for more than one level in a single statement, so the statement below would not work:

options.LoadWith<Apartment>(apartment => apartment.CurrentLease.PrimaryTenant);

You need to break it into two statements:

options.LoadWith<Apartment>(apartment => apartment.CurrentLease);
options.LoadWith<Lease>(lease => lease.PrimaryTenant);

If you have a scenario where some object has a collection of objects, and each of those objects has some collection of objects you can’t eager load it all at once. You’d think that the statement below would load all apartments and leases when you retrieve a building, but it doesn’t.

options.LoadWith<Building>(building => building.Apartments);
options.LoadWith<Apartment>(apartment => apartment.Leases);

This will retrieve the leases on the apartment as needed, i.e. lazy load. I’m not sure if this is a bug or a deliberate limitation, I haven’t been able to find any information on the issue.

Adding a calculated property to the data load options will be ignored so don’t bother, i.e. a property that is not mapped to a database field.

The last important item to note is that you need to assign the load options to the data context before requesting any data, and you can’t change the load options after requesting data from the data context. This is the biggest downside of the data load options.

Disclaimer: This post is based on Orcas CTP June 2007

LINQ to SQL – Business Object Validation

Validation of LINQ entities on SubmitChanges() is handled through a partial method called OnValidate(), all you need to do is implement this method in your (non generated) partial class and the framework will call the method when it submits changes to the database for that entity.

You’ll notice the return type is void for OnValidate(), if validation fails you are expected to raise an exception.

One problem with this validation method is that you don’t know if the validation is for a new entity or an update to an existing entity. There is a interim solution to this problem that will be discussed in a later post, but Microsoft have changed the OnValidate() method’s signature for the RTM release, it will have a enum parameter that will define if the validation is for an insert, update, or delete. Read more about the change here:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2060651&SiteID=1

Disclaimer: This post is based on Orcas CTP June 2007

LINQ to SQL – Cannot set the discriminator value

Problem: With inherited classes in LINQ you need to specify a discriminator flag that tells LINQ which class to instantiate. Now sometimes the data designer won’t let you set this value. It’ll give you the error “Property value is not valid. Discriminator Value “YOUR VALUE” is already being used”.
Reason: It’s a bug!!!
Work Around: Sometimes closing and reopening your IDE works otherwise you’ll need to edit the generated code and reopen the data designer. Find the base class in the generated code and add the following attribute:

[InheritanceMapping(Code="VALUE", Type=typeof(CHILDCLASS))]

Disclaimer: This post is based on Orcas CTP June 2007