Dot Net Tricks

Articles about .NET, ASP.NET, C#, Object Oriented Programming and Agile Methodologies
Welcome to Dot Net Tricks Sign in | Join | Help
in Search

Software Theosophy

Lazy Load: My Favorite Design Pattern

I’m hoping this can be a quick post.  I’d just like to share my favorite design pattern: “Lazy Load” or “Load on Demand”.  You’ll find this pattern in Martin Fowler’s Patterns of Enterprise Architecture Book, and he has a description of the pattern on his website. 

 

Lazy Load usually deals with a call to a database.  Many O/R Mappers support lazy load.  Basically, it enables you to load related objects and data in an object model only when you need them.  For instance, if you have a customer object, and that customer has orders that she has placed in the database, you don’t want to have to load all the orders (and the order lines, and the products in the order lines, etc.) every time you need to use the customer object for displaying their name.  Grabbing all this related data every time you instantiated the customer object would mean a lot of unnecessary database calls and object creation.  On the other hand, you want to be able to get the orders when you DO need them, and only get them once.  For instance, if you access the Orders several different times from the same screen or page, you probably only need fresh data the first time you access them, not on every call to customer.Orders.

 

Lazy load enables this functionality, usually in a method or property by first checking to see if a private instance variable.  The code might look something like this:

 

public class Customer

{

       private List<Order> _orders;

 

       public List<Order> Orders

       {

              get

              {

                     if (this._orders == null)

                     {

                           this._orders = OrderRepository.GetOrdersByCustomerId(

                                  this.CustomerId);

                     }

                     return this._orders;

              }

       }

}

 

The “OrderRepository” class may just be a data access class that loads orders, or you might use an O/R Mapper to retrieve the related data.  In this way, you only load the data when you need it, because if you never call the Customer.Orders property, the _orders variable never gets loaded and remains null.  If it does get called, it only gets called once for the life of the object.

 

Most developers have used this pattern at some point either knowingly or unknowingly for data access or object mapping.  But I like to use this pattern all the way in my presentation layer, even when I’m not doing anything that has to do with data access. 

 

For example, say I have an ASP.NET page where I need to edit or add a new customer.  I can approach this problem a more traditional way:

 

public partial class EditCustomer : System.Web.UI.Page

{

       protected Customer _customer;

 

       protected void Page_Load(object sender, EventArgs e)

       {

              int customerId = Convert.ToInt32(

                     Request.QueryString["customerId"]);

 

              this._customer = CustomerRepository.GetByKey(customerId);

 

              if (!Page.IsPostBack)

              {

                     //do some stuff here

              }

       }

}

 

In most cases, this will work fine.  You can then display the customer on the form thru databinding expressions or by setting the properties of some textboxes.  There is nothing wrong with this code. However, there may be instances where on a post back, you will do things on the page unrelated to the customer object.  For instance, you might perform some server-side validation that needs to occur before you ever access the customer object (yes, I know some frameworks have you do server validation in the domain object, but humor me.)  Or you may have tabs the page shows one panel and hides the others.  In all these cases, there are post-backs but no need for the customer data.  However, at some point, the user will need to hit a “Save” button and the page WILL need the customer data, so it can populate it.  You could of course copy and paste the code above into the save method (ugh!) or refactor the customer loading code above into its own method (better).  But now you need to know when to call that LoadCustomer() method from various places in your page depending on the situation.

 

Instead of all this, I simply standardize on the lazy load pattern in my page for getting the customer object when I need it.  This way I don’t have to think about when to load the customer object and when not to, the lazy load pattern does it all for me.  My stub code for our imaginary EditCustomer.aspx page might look like this:

 

private Customer _customer;

 

public Customer Customer

{

       get

       {

              if (this._customer == null)

              {

                     int customerId = Convert.ToInt32(

                           Request.QueryString["customerId"]);

 

                     this._customer = CustomerRepository.GetByKey(customerId);

              }

 

              return this._customer;

       }

}

 

protected void Page_Load(object sender, EventArgs e)

{

       if (!Page.IsPostBack)

       {

              //do some stuff here

              this.OrderGridView.Datasource = this.Customer.Orders;

              this.OrderGridView.Databind();

       }

}

 

protected void SaveButton_Click(object sender, EventArgs e)

{

       if (this.Page.IsValid)

       {

              //save the customer here

              this.Customer.FirstName = this.FirstNameTextBox.Text;

              //etc etc/

       }

}

 

In this way, I only load the customer when needed.  Notice also that I don’t get every object or collection that I need right here in the page.  There’s usually a “root” object on a screen or page that you are working with, and you should get anything related to that root object thru the object model. For instance, in this case, the Customer is our root object because that is what we are editing.  However, if I need to show the customer’s orders on the page, I won’t create a bunch of lazy loading code directly in my page.  I already have the customer, I should just go through the Customer’s Orders property and use what is already in the object model:

 

if (!Page.IsPostBack)

{

       //do some stuff here

       this.OrderGridView.Datasource = this.Customer.Orders;

       this.OrderGridView.Databind();

}

 

I often see developers that are new to objects or O/R Mapping making unnecessary calls to the business layer, repository or static methods to load various objects and collections in a piecemeal fashion.  This creates a lot of unnecessary code.  In most cases, you can get anything you need from the root object, then go thru that root object’s hierarchy for any related information.  If you find that your O/R Mapper, code-generated business layer, or home-made object model does not have the related data, you should probably add a property or method to the object model, NOT to the code-behind.  I only use the lazy load pattern in my code behind or screen to get some root object (usually by the database’s primary key), whenever possible.  For example, if in the code above I needed to change the page to display only the past 30 days of orders, not ALL the customer’s orders, I would not add this call to the page directly. I would add it as an instance method or property the Customer object.  Then in my page, I would only need to change it to do something like this:

 

if (!Page.IsPostBack)

{

       //do some stuff here

       this.OrderGridView.Datasource = this.Customer.GetRecentOrders(30);

       this.OrderGridView.Databind();

}

 

I’m still going thru the Customer object, but just accessing a newly added instance method called GetRecentOrders that takes a number of days as a parameter. 

 

So in summary:

 

DO use the lazy load pattern to get the initial (ROOT) objects that your page may need.

DO use lazy load in your business layer’s object model to get related data thru properties or methods.

DON’T use lazy load data in your page to get objects or collections that are related to something you’ve already got.  Add those to your object model instead.

Published Tuesday, September 12, 2006 7:58 AM by Fregas
Filed Under: , ,

Comments

 

Michael said:

This was an excellent article.  Before I read this article I conceptually understood Lazy Loading.  I just was not sure of the best method to implement it. Now I am.  

Thanks
March 9, 2007 8:26 AM
Anonymous comments are disabled

About Fregas

Craig is currently the Lead Developer in Fort Worth, Texas for Enilon Group, a web development firm. He has been programming since 3rd grade (using the Commodoore PET) and professionally for the past 7 years. He has written several articles for ASPToday.com and co-authored the book "Beginning Web Programming using VB.NET and Visual Studio .NET" Currently, his favorite programming language is C#, but he has programmed in Visual Basic, T-SQL, Ruby, ColdFusion, ASP 3.0/VBScript, ASP.NET, Javascript, Java and even Pascal. Besides programming, Craig is best known for his cooking and his somewhat offbeat sense of humor.

This Blog

Post Calendar

<September 2006>
SuMoTuWeThFrSa
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

Syndication

Powered by Community Server, by Telligent Systems