Published: 09 Sep 2010
By: Dino Esposito

Last month I took the challenge of trying to compare Entity Framework (EF4) and NHibernate (NH) in a hopefully unbiased and feature-driven way. In this article, I'll start looking into some programming features such as lazy loading.

Contents [hide]

The NHibernate Comparison of Entity Framework series

  • Part 1 A comparison on multiple database support in the Entity Framework and NHibernate O/RMs.
  • Part 2 Last month I took the challenge of trying to compare Entity Framework (EF4) and NHibernate (NH) in a hopefully unbiased and feature-driven way. In this article, I'll start looking into some programming features such as lazy loading.
  • Part 3 This article is about fetch plans-a recognized and common way for developers to instruct the O/RM about the structure of the SQL you desire.
  • Part 4 A Feature-driven Comparison of Entity Framework and NHibernate-2nd Level Caching
  • Part 5 A Feature-driven Comparison of Entity Framework and NHibernate - Self-tracking entities
  • Part 6 A Feature-driven Comparison of Entity Framework and NHibernate - Queries
  • Introduction

    In the previous article, I focused on the support that both frameworks offer for working with multiple databases. Drawing the conclusions for that article, at some point I used a few words that probably summarize very well most of the difference between the frameworks. All in all, there's no significant difference between the two frameworks if you just count things you can or cannot do. However, a sort of different philosophy emerges to characterize differently the two frameworks. Entity Framework (version 4) tends to offer extra tools to make things simpler and to lower the learning curve as much as reasonably possible. NHibernate, instead, keeps things close to their natural level of complexity. I suggest you keep this point in mind when evaluating the framework to make your choice.

    In this article, I'll start looking into some programming features such as lazy loading.

    What's Lazy Loading, Anyway?

    Lazy loading is a necessary feature that any O/RM framework today can't just avoid supporting. Both NHibernate and EF4 are no exception and fully support it. However, the implementation is a bit different. Let's start refreshing the definition of "lazy loading". Lazy loading refers to an object's ability of loading some of its own data not upon initialization but at a later time, typically when the object gets a specific request for that data. According to Martin Fowler and "Patterns of Enterprise Application Architecture", an object that supports lazy loading is an object that at any time may lack some of the data it is supposed to contain and expose, but knows how to get it. (You can read about the Martin Fowler's perspective also here http://martinfowler.com/eaaCatalog/lazyLoad.html.)

    When it comes to domain models, lazy loading is a key feature as it keeps as low as reasonably possible the size of object trees currently loaded in memory. When you load, say, a customer object you may be bringing up to memory also all of the customer's orders, and all of the details of individual orders, and all of the product information for each order detail of each order of each customer. And so forth.

    Lazy loading is certainly a technique to optimize the performance of some code, but it doesn't deliver its benefits in just any scenarios. Essentially, lazy loading is still about "loading some data". In this regard, it doesn't save you any work. If you're going to use a given piece of data, then lazy loading or not, you're going to go to the database (or wherever else) and pull data back. The whole point of lazy loading is "when" you go to the database (or wherever else). Sometimes, getting some related data later better distributes the efforts of data retrieval and results in a perception of improved performance. The major benefits of lazy loading come when the data to retrieve is distributed in a way that requires multiple accesses. Imagine the classic scenario of customers and orders. You likely need one access to read the customer information and one access to load all of the orders. Depending on how your client layer is structured, it may be that showing the orders is optional or happens after a number of steps through the user interface. In this case, you may decide to lazy-load order information to get at it only if the user specifically asks for that. Likewise, you can choose to load the order information in the background as the user proceeds through the features of the user interface. In other situations, lazy loading may be helpful to break data retrieval in distinct steps so that the most critical portion of the user interface shows up quickly while the rest is delayed. This may be the case when you have pictures or large chunks of information to load associated with a customer: even though the information may be in the same table row, breaking the load in two steps may be helpful.

    Lazy Loading and O/RM Frameworks

    A key aspect of lazy loading is that related properties are loaded automatically for you only when (and if) you access them. As a developer, you don't have to write extra code to get certain properties lazy-loaded. In addition, the query that retrieves extra data is only run if the objects are not already loaded in the current O/RM session.

    This widely accepted definition of lazy loading was not matched by the design of the first version of Entity Framework. EF1, in fact, doesn't implement the Lazy Loading pattern at least according to its common interpretation. EF1, instead, supports something similar but actually different - deferred loading. The key difference between classic lazy loading and deferred loading is that deferred loading requires an explicit command from the code. Sounds like a picky detail? Look at the following code:

    You first get a reference to a customer and then you access its list of orders. How many orders are you actually getting? The answer really depends on how (and if) the underlying framework implements lazy loading. In NHibernate (and also LINQ-to-SQL) the correct answer is "just the number of orders actually stored in the data store." What about Entity Framework?

    In EF1, the answer would be "zero." In the latest EF4, the answer is "zero" or "just the number of orders actually stored in the data store" depending on a particular setting. With deferred loading, an explicit call is required to make access to a database:

    The rationale behind this decision has been widely discussed in several blog posts and can be summarized with the will of having people to be explicit about database calls. This decision was sharply blamed in the Vote-of-no-confidence paper and in some way brought to a shift of perspective in EF4.

    In the latest EF4, you have support for a classic form of lazy loading which lines up Entity Framework with LINQ-to-SQL and any other O/RM tools and, furthermore, it shields client code from having visible dependencies on the plumbing of the O/RM framework being used.

    Lazy Loading and Entity Framework

    So EF4 supports lazy loading but it is limited to navigation properties. In the EF jargon, a navigation property is a property that references related objects, such as the Orders property for a Customer object. In other words, you are not allowed to have native lazy loading on some Photo property of a Customer object. Lazy loading can be configured on a per context basis meaning that lazy loading is applied to all navigation properties within the reach of the current data context object or none of them.

    Lazy loading is activated through the Boolean property LazyLoadingEnabled defined on the ObjectContext object, as shown below.

    Note that by default LazyLoadingEnabled is set to false. However, the Visual Studio wizard that generates the entity model for you automatically sets the the LazyLoadingEnabled property to true in the constructor of the custom object context class.

    As mentioned, Entity Framework doesn't natively support lazy loading for scalar (non-navigation) properties. Likewise, it doesn't supply a mechanism to choose which navigation properties are to be lazy-loaded. In this regard, it is an all-or-nothing feature.

    However, if you opt for a POCO model and keep proxy generation enabled (the default), then lazy loading is enabled on a navigation property only if it is marked virtual. Subsequently, not marking the property virtual will drop lazy load on it anyway. (Needless to say, if you code your model manually you can achieve lazy-loading just anywhere you want.)

    Lazy Loading and NHibernate

    Quoting from a recent Ayende's post, NHibernate is lazy - just live with it. What works best in most of the cases is just leaving things the default way, which means that all navigation properties are lazy. This said, however, you can decide to disable lazy-loading for a class or a specific navigation property declaratively within the mapping files. You enable lazy loading declaratively using the lazy attribute in the mapping file for the class or the navigation property.

    For lazy properties NHibernate builds a proxy object that knows how to retrieve data if that has not been cached yet. This requires that lazy properties are declared as virtual.

    NHibernate also doesn't currently support lazy loading of scalar properties such as a property that represents a BLOB column. However, this feature has been announced for version 3.0. Some interesting details about the implementation of the feature are available here. In particular, it is interesting that all lazy column properties are being loaded at the same time.

    Summary

    Before the advent of EF4, the topic of lazy loading marked a significant difference between Entity Framework and other O/RM products. Expressions like "deferred loading" and "lazy loading" if taken out of their O/RM context mean nearly the same and are reasonably considered as synonyms. On the other hand, design patterns have been invented, and became popular, as a way to refer a particular feature or aspect using a unique and unambiguous term. Taking this a little bit farther, we could say that "lazy loading" if meant to be the name of a design pattern can't be aliased in other ways and doesn't support synonyms: when you say lazy loading you can't use synonyms and mean exactly what the definition of the pattern states.

    Frankly, the notion of deferred loading in EF1 broke this state of things. As I see thing, that was the major drawback, far beyond the technical design considerations for choosing deferred loading over implicit, lazy loading. Properly used, both classic lazy loading and EF1 deferred loading provide the same.

    Anyway, with EF4 the support for lazy loading in Entity Framework and NHibernate is equivalent. But the upcoming NHibernate 3.0 will take NHibernate one step farther with the long-awaited introduction of lazy-loaded scalar properties.

    The NHibernate Comparison of Entity Framework series

  • Part 1 A comparison on multiple database support in the Entity Framework and NHibernate O/RMs.
  • Part 2 Last month I took the challenge of trying to compare Entity Framework (EF4) and NHibernate (NH) in a hopefully unbiased and feature-driven way. In this article, I'll start looking into some programming features such as lazy loading.
  • Part 3 This article is about fetch plans-a recognized and common way for developers to instruct the O/RM about the structure of the SQL you desire.
  • Part 4 A Feature-driven Comparison of Entity Framework and NHibernate-2nd Level Caching
  • Part 5 A Feature-driven Comparison of Entity Framework and NHibernate - Self-tracking entities
  • Part 6 A Feature-driven Comparison of Entity Framework and NHibernate - Queries
  • <<  Previous Article Continue reading and see our next or previous articles Next Article >>

    About Dino Esposito

    Dino Esposito is one of the world's authorities on Web technology and software architecture. Dino published an array of books, most of which are considered state-of-the-art in their respective areas. His most recent books are “Microsoft ® .NET: Architecting Applications for the Enterprise” and “...

    This author has published 54 articles on DotNetSlackers. View other articles or the complete profile here.

    Other articles in this category


    A Feature-driven Comparison of Entity Framework and NHibernate-2nd Level Caching
    Where would you place caching in your layered solution? Two main patterns exist for caching in appli...
    A Feature-driven Comparison of Entity Framework and NHibernate - Queries
    Let's explore what Entity Framework and NHibernate has to offer when it comes to their query capabil...
    A Feature-driven Comparison of Entity Framework and NHibernate—Fetch Plans
    This article is about fetch plans-a recognized and common way for developers to instruct the O/RM ab...
    A Feature-driven Comparison of Entity Framework and NHibernate - Self-tracking entities
    In this article, Dino Esposito introduces self-tracking entities.
    .NET type generation for NHibernate mapping collections
    An overview of .NET type generation for NHibernate mapping collections.
    Top
     
     
     

    Please login to rate or to leave a comment.