Tuesday, January 22, 2013

Deferred Or lazy Loading Entity Objects

To have the lazy or deferred loading for the Entity Objects (POCO), there are some settings to be taken care of first.


  • Ensure the proxy creation is on for the Context.
  • Ensure the lazy loading is turned on.
  • Make sure the class is not Sealed and is Public
  • Declare the navigation properties you want to Lazy Load as Virtual

Example:

// Proxy creation
this.ContextOptions.ProxyCreationEnabled = true;
// Lazy Loading.
this.ContextOptions.LazyLoadingEnabled = true;


    public class Customer
    {
        public string CustomerID { get; set; }
        public string CompanyName { get; set; }

        List<Order> orders = new List<Order>();

        public virtual List<Order> Orders
        {
            get
            {
                return orders;
            }
            set
            {
                orders = value;
            }
        }
    }

Once the above things are taken care of, lazy loading is ready to run in an application.

If you have a program which loads Customer and if you iterate through each order for a Customer, each Order in customer will load only when it is accessed from the customer as a navigational property. For example, if the customer has 5 orders, you could see 6 queries if you observe in the SQL Profiler. First query to load the Customer and the rest 5 queries, to load the Orders in the Customer when they are accessed through navigational property from Customer.

Note: If you wonder how can a plain object gets the power to lazy load, like an invisible event getting triggered to load it by itself, the answer is,

Once you set the navigational property as virtual, and the right settings are On for the context, entity framework overrides the plain object navigational property with its Entity Framework Proxy Object for that navigational property type, which is capable of calling the context and getting its values filled when it is accessed from the class.

Thursday, January 17, 2013

Explicit Loading Entity Objects


There are two ways with which we could implement explicit load for entity objects.

1. Using Load() method
2. Using CreateSourceQuery() and Attach()


  • Load() Method


To load related entity objects of an object explicitly, we could use Load() method. When we call Load() method on an object to get its child object collection, ValidateLoad<TEntity> is called before loading the collection. If we use Load() method and if the collection is already loaded in the object context, it enforces one of the MergeOption specified.

MergeOptions are:

AppendOnly: Objects already present in ObjectContext are not loaded again from data source.
OverwriteChanges: Objects are always loaded overwritting the changes in the ObjectContext.
PreserveChanges: Objects are always loaded but changes in the ObjectContext are preserved.
NoTracking: Objects are maintained in detached state and are not tracked.

To know whether the object collection has already been loaded to ObjectContext or not, we could use IsLoaded() which returns true/false. But when we initiate a call to Load() method, IsLoaded() is not automatically checked.

Note: When we call Load() method in a loop, each object service tries to open a new data reader. This may fail if we have not set the "multipleactiveresultsets=true" in the connection string.Once we load the result to List<T>, the data reader connection is closed.

Example:


// Load the orders for the customer 
if (!customer.SalesOrderHeader.IsLoaded)
{
    customer.SalesOrderHeader.Load();
}



  • CreateSourceQuery() and Attach()

Using CreateSourceQuery(), we get new instance of ObjectQuery<T> that returns the same set of objects. This method is particularly useful when going for more complex joins, unions and filtering. It can be also used to return the same object in detached state by using the MergeOption, NoTracking. CreateSourceQuery() is used to filter objects in an EntityCollection<TEntity> to enable us to bind only those filtered objects. The result which we get using the CreateSourceQuery() is then attached to the object using Attach() method.


CreateSourceQuery() may result in an "InvalidOperationException" if the object is in Added state or when the object is in Detached state with a MergeOption other than NoTracking.

Entity States are:

Detached: Object exists but not tracked by Object Services. Operations that can make the entity object Detached are


  1. Entity object is created and not added to ObjectContext
  2. When object removed from ObjectContext by calling Detach
  3. When the object is loaded with MergeOption, NoTracking
Unchanged: Object has not been modified since it was loaded or since the last time the SaveChanges method was called.
Added:Object is been added to the ObjectContext, but the SaveChanges method is not called yet.
Deleted: Object is been deleted from ObjectContext using DeleteObject method.
Modified: Object is changed or modified, but SaveChanges method is not been called.



Example:


// Return the customer's first five orders with line items and
// attach them to the SalesOrderHeader collection.
customer.SalesOrderHeader.Attach(
  customer.SalesOrderHeader.CreateSourceQuery().Include("SalesOrderDetail").Take(5));



Eager Loading Entity Objects

To eager load an entity object, all we need to use is key word Include. By using Include() method, we are telling entity framework to get a particular object collection when we query for the parent object. Irrespective of lazy loading is turned on or off in the context, eager loading works by just using the Include key word in the entity loading query.

public IQueryable<MyEntity> GetMyEntities()
{
       return this.MyEntities.Include(e => e.SubObjectCollection);
}
In the above example, SubObjectCollection is loaded as soon as the MyEntities loaded. The process of using Include in the query so that we could load a sub object of an entity when it's loaded is called eager loading.