Entity Framework 4.0 Beta 1 – POCO Lazy Load and Code Generation of ObjectContext

In my first post about the 4.0 beta 1 bits I explored how we can work with our own POCO classes with the Entity Framework. In this post I will expand the example a little and figure out if and how we can do automatic lazy loading. Furthermore i will see if I can use the build in T4 template support to autogenerate an ObjectContext for our POCO entities.

The Model

I want to create a common scenario with an order, orderline, product and customer, so I start out with writing the following classes:

    1 public class Customer

    2 {

    3     public virtual ICollection<Order> Orders { get; set; }

    4     public virtual int Id { get; set; }

    5     public virtual string FirstName { get; set; }

    6     public virtual string LastName { get; set; }

    7     public virtual string Address { get; set; }

    8     public virtual string Email { get; set; }

    9 }

   10 public class Order

   11 {

   12     public virtual ICollection<OrderLine>

   13         OrderLines { get; set; }

   14     public virtual Customer Customer { get; set; }

   15     public virtual int Id { get; set; }

   16     public virtual DateTime CreatedDate { get; set; }

   17     public virtual int Status { get; set; }

   18 }

   19 public class OrderLine

   20 {

   21     public virtual Product Product { get; set; }

   22     public virtual Order Order { get; set; }

   23     public virtual int Id { get; set; }

   24     public virtual double ItemPrice { get; set; }

   25     public virtual int Quantity { get; set; }

   26 }

   27 public class Product

   28 {

   29     public virtual ICollection<OrderLine>

   30         OrderLines { get; set; }

   31     public virtual int Id { get; set; }

   32     public virtual string Name { get; set; }

   33     public virtual string Description { get; set; }

   34     public virtual double Price { get; set; }

   35 }

Then I go ahead and create the Entity Framework Model exactly like the Poco classes.

image

Notice the navigation properties have the right pluralization. If you generate your Entity Model from an existing database notize that you now have the option to pluralize or singularize generated object names:

image

T4 Code Generation

This time I dont want to manually write my objectcontext implementation. I want to code generate it, so that when i update my Entity Model the ObjectContext is automatically updated as well.

In version 1.0 of the Entity Framework you had to create a SingleFileGenerator and hook into EFs codegeneration events, and it was not a very likeable costumization story. Because of all the feedback on this, The ADO.Net Team decided to handle code generation with T4 templates instead.

This is truly sweet, and as it is deeply integrated with the Entity Framework its very easy to get started. As an example we will add a t4 template generator to our project and modify it to work with our POCO classes.

image

First we select our .edmx file and go to the entity designer. Then we right-click anywhere on the workarea and choose “Add new Artifact Generation Item”. Then we choose the ADO.NET EntityObject Generator:

image

This creates a .tt file with a sub .cs file. The .tt file is the template and the sub cs. file is the result of running the code generation on the template. When you change the .tt file and save the .cs file will be updated – you can also right click the .tt file and choose “Run custom tool”.

Now we open op the template file, and its not really as nice an interface as we are used to with Visual Studio – no syntax-highlighting or intellisense really makes it a challenge to edit:

image

To fix that we use the brand new Extension Manager (Tools > Extension Manager) in Visual Studio to get the Free Edition of the Tangible T4 editor – its not as feature rich as the Clarius Visual T4 one, but its free and a huge improvement:

image

This makes our template file look a lot more appealing, and the intellisense is simply invaluable – trust me, you need this one. The .tt file now looks like this:

image

So now we are equipped to remove the bits of the code generation that we don’t want. We want to get rid of any entities being generated and leave only the context bits. Its basically three sections that need to go - see the attached project for the resulting file. We also need to add an import to the namespace that contains our Poco classes, as so that these classes are used instead of the generated entities that we just have removed.

Requirements for Using Persistence-Ignorant Objects

In order to support deferred loading of related objects and change tracking some requirements do need to be fulfilled by the POCO classes.

What happens behind the scenes is, that a proxy object is created that inherits from your POCO object. This proxy object is responsible for handling lazy loading and change tracking. The requirements are:

  • Poco class must be public, and not sealed or abstract, and implement a default constructor with no parameters.
  • Poco class must NOT implement IEntityWithChangeTracker or IEntityWithRelationShips.
  • Poco class properties mapped to conceptual model must be public and virtual.
  • The mapped Navigational property must be declared virtual and must not be sealed.
  • One-to-Many and Many-to-Many navigational property (OrderLine on Order for instance)  must be mapped to properties that return a type implementing ICollection.

There are actually generated two kinds of proxies: One that handles lazy loading and one that handles change tracking. If you only mark navigational properties virtual, you will not get the change tracking proxies.

Eager Load vs. Lazy Load

So now we want to try out out, and we could do something like this:

    1 

    2using (var context = new OrderModelContainer())

    3{

    4     var orders = from o in context.OrderSet select o;

    5 

    6     foreach (var order in orders)

    7     {

    8         Console.WriteLine(order.CreatedDate);

    9         foreach (var orderline in order.OrderLines)

   10         {

   11             Console.WriteLine("  " + orderline.Quantity

   12                         + " " + orderline.Product.Name

   13                         + " of $" + orderline.ItemPrice);

   14         }

   15     }

   16 }

We try to print the orderlines for each order – but the result is without the orderlines:

image

In Entity Framework version 1.0 we would have to explicitly eager load the related objects, and you can of course still do this:

    6 var orders = from o in

    7              context.OrderSet.Include("OrderLines.Product")

    8              select o;

In many situations this is a good thing, as you have control over how many times your database is hit on a query, but it also clutters your code with at lot of explicit includes, and more often than not developers are surprised that the related collection of objects – orderlines for instance – is empty when called. It just seems more logical with lazy loading.

So instead you can now in EF4 decide to let the related objects load silently when they are called, resulting of course in further calls to the DB.

The lazy load or deferred load option is set on the context, and is disabled by default:

    1 using (var context = new OrderModelContainer())

    2 {

    3     context.ContextOptions.DeferredLoadingEnabled = true;

    4 

    5     var orders = from o in context.OrderSet select o;

    6 

    7     foreach (var order in orders)

    8     {

    9         Console.WriteLine(order.CreatedDate);

   10         foreach (var orderline in order.OrderLines)

   11         {

   12             Console.WriteLine("  " + orderline.Quantity

   13                         + " " + orderline.Product.Name

   14                         + " of $" + orderline.ItemPrice);

   15         }

   16     }

   17 }

Both the eager loaded and the lazy loaded produces the following result:

image

Setting the lazy load on the context seems very limited, and it would be much more helpful to the developer in a real world scenario if you could define the load strategy per navigation property.

The best that i can see as an option is that you enable lazy loading, and then handle the cases you know are going to do a lot of DB roundtrips with eager loading and do a sort of combo.

All in all i still think that EF4 is gigantic leap forward, and so far it has been surprisingly easy to make everything run as expected.

Resources

Friday, May 29, 2009 1:25:03 AM (Romance Standard Time, UTC+01:00)
Nice post. Im just starting with .Net 4.0. BTW could you share your Visual Studio colors settings, i really like it?? :)
Tom
Friday, May 29, 2009 7:54:29 PM (Romance Standard Time, UTC+01:00)
Thanks. Sure here you go:

http://devtalk.dk/content/binary/colorsonly.rar
Saturday, May 30, 2009 1:59:00 AM (Romance Standard Time, UTC+01:00)
Thanks. BTW are you planning on posting something to show how to implement Repository and UnitOfWork patterns with EF4?

Tom
Tom
Sunday, May 31, 2009 2:54:43 PM (Romance Standard Time, UTC+01:00)
Actually yes - I am actually currently working on that, and another one with more mapping scenarios.
Monday, June 01, 2009 11:44:54 PM (Romance Standard Time, UTC+01:00)
cool when are you going to publish that?
Tom
Tuesday, June 09, 2009 8:29:21 PM (Romance Standard Time, UTC+01:00)
Just published post on Repository and UnitOfWork with EF4: http://bit.ly/POcTi
Thursday, November 26, 2009 10:15:01 AM (Romance Standard Time, UTC+01:00)
I am evolving my domain (and therefore conceptual) model in parallel with the database model. Therefore, if I click on "Update Model from Database..." in the entity designer, it updates not only my storage model, but also the conceptual model. This often messes up my conceptual model.

Do you know a way how I can update my storage (automatically), without the conceptual model being updated?
Marcel
Tuesday, December 15, 2009 3:58:36 PM (Romance Standard Time, UTC+01:00)
Great post!
I'm having trouble figuring out this part:
"So now we are equipped to remove the bits of the code generation that we don’t want. We want to get rid of any entities being generated and leave only the context bits. Its basically three sections that need to go - see the attached project for the resulting file."

I've looked at both the DTO and POCO templates, but both seem to have entity code in them.

Thanks,
Voss
Tuesday, December 15, 2009 7:31:31 PM (Romance Standard Time, UTC+01:00)
Hey Voss, thanks for your comment. Glad you liked the post :)

Im not completely sure what you mean, but the point in this example is to use the T4 template, to automatically generate the objectcontext, but not the entities.

Therefore i add the template to the project, and remove the part of the the template that generates the entities leaving the objectcontext.

The difficult bit obviously is to finde the bit to remove. You have to look for the part enclosed in the "entities" region (search for "Template_RegionEntities" in the tt file) and delete until somewhere before "Reusable Template Sections".

All comments require the approval of the site owner before being displayed.
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):

Live Comment Preview