Tuesday, February 15, 2011

Eager loading EF4 entities with RIA services using Silverlight 4.0

I have recently come across a problem trying to access navigation properties using EF4 from the client side. Consider the following Data structure:



In this example, the LeaveLog table has a reference to the LeaveType table, therefore making a Navigation Property "LeaveType". 

Step 1: Disable lazy loading
The first stumbling block when trying to access these navigation properties from the client side was due to the fact that LazyLoading was enabled by default. This is not possible when transferring your entities through services, as described here. You therefore need to turn off lazy loading by following these steps:

1. Double click on your .edmx file in the solution explorer
2. Right click anywhere in the white space and click "Properties"
3. In the properties window, set "LazyLoadingEnabled" to false.

You will then see that in the generated file, the following line will be added:

  this.ContextOptions.LazyLoadingEnabled = false;

However, if you build and run the solution, you will still run into trouble accessing the navigation properties (they will still return null).

Step 2: Add .Includes to the RIA service
In this situation where you are using RIA services, you should have methods in the RIA service such as the following:

 public IQueryable<LeaveLog> GetLeaveLogs()
        {
            return ObjectContext.LeaveLogs;
        }

This exposes the "LeaveLogs" collection to the client side. However, you need to actually specify the navigation properties to return along with the query by adding ".Include" methods like this:

public IQueryable<LeaveLog> GetLeaveLogs()
        {
            return ObjectContext.LeaveLogs.Include("Employee").Include("LeaveType");
        }

What this means is that when querying a LeaveLog from the client side, the "Employee" and "LeaveLog" navigation properties will be propagated with data.

Final Step: Add the [Include] attribute to the navigation properties
At this point, even after adding the .Includes, you are not finished. You need to actually add an [Include] attribute above the generated Navigation Properties. I edited the .tt template to include this attribute so that going forward all navigation properties are accessible.

1. Open your .tt template file
2. Locate the section where Navigation Properties are set
3. Add [Include] as an attribute beneath the [DataMember()] attribute
4. Add  using System.ServiceModel.DomainServices.Server; to the using section in the template.
5. Save and run the template.

And thats it?
After following these steps, you should be able to access your navigation properties from the client side. This seems like a lot of effort to get what I'd expect to happen automatically if Lazy Loading is disabled. My opinion is that there should be an option to at least automatically include the ".Include" methods in the generated code to save us the effort.


No comments:

Post a Comment