In a previous post we discussed about creating data forms for showing master-details data representations with Visual Basic 2008 and the ADO.NET Entity Framework and we said that using strings within the eager loading technique could cause the loss of the benefits provided by the LINQ strongly typed approach.
I then found a blog post by Matthieu Mezil (Microsoft Visual C# MVP), who solved the problem implementing a custom Include method using lambda expressions instead of strings, taking the advantage of the strongly typed approach. Matthieu's code is in Visual C# with his help we converted the code into Visual Basic 2008.
The code is quite short, but it requires a good knowledge of LINQ, so you'll find links to the MSDN library for each object we will utilize.
Let's retake the demo application we saw in the previous post then let's add a new module. In this module we must first add the following Imports directives:
Imports System.Runtime.CompilerServices
Imports System.Data.Objects
Imports System.Linq.Expressions
Imports System.Reflection
Once we've done this, let's type the following code which implements an extension version of the Include method. This is the code about the new module and that we'll comment below:
<Extension()> Module ObjectQueryExtension
<Extension()> _
Function Include(Of T)(ByVal MainQuery As ObjectQuery(Of T), _
ByVal SubSelector As Expression(Of Func(Of T, Object))) _
As ObjectQuery(Of T)
Return MainQuery.Include(CType(CType(CType(SubSelector.Body, _
UnaryExpression).Operand, _
MemberExpression).Member, _
PropertyInfo).Name)
End Function
End Module
Extension methods must be adorned with the Extension attribute and must be exposed by modules adorned with the same attribute. The Include method requires a generic type Of T. The first argument the method receives is of type ObjectQuery(Of T), that represents, in a strongly typed way, a query executed versus the Entity Data Model. In our case the ObjectQuery is constituted by the NorthwindContext.Categories object. The secund argument is of type Expression (Of TDelegate), and is a strongly typed representation of a lambda expression that is structured as an expression tree.
The method body invokes the Include method versus the ObjectQuery instance that it received (in our sample it's always the NorthwindContext.Categories).
The lambda expression body is converted into an UnaryExpression. The result of this expression (Operand) is then converted into a MemberExpression, which is the infrastructure for accessing fields or properties which are then accessed via the reflection.
Invoking this method is quite easy. If we would apply the method to the demo application we saw in the previous post, we can replace the line of code for the eager loading as follows:
'Dim dataSource = NorthwindContext.Categories.Include("Products")
Dim dataSource = NorthwindContext.Categories.Include(Function(c) c.Products)
You can surely notice the difference. We are no more passing a string, because we are now passing a lambda expression that allows us working in a strongly typed way (with many advantages from this). The local type inference correctly assigns the Categories type to the c object and the ObjectQuery(Of Categories) type to the dataSource one.
If you try to run the application you'll obtain the same result of the previous time, but this time we retrieved data with a more efficient and "managed" approach.
Alessandro