Friday, April 6, 2012

Enabling Deferred or Eager Loading of Associated Entities

Enabling Deferred or Eager Loading of
Associated Entities
As mentioned in a note at the beginning of this chapter, LINQ to SQL lazy loads associated entities by
default; EF doesn ’ t support lazy loading. According to the EF development team, a basic design
principle is avoiding enabling by default features that might be unknown and unwanted by developers;
avoiding default lazy loading adheres to that principle. The following sections describe deferred loading or
explicit loading , EF ’ s approach that corresponds approximately to LINQ to SQL ’ s lazy loading , and eager
loading , which is very similar to that for LINQ to SQL.
Deferred Loading with the Load() Method
Deferred loading returns associated entities and EntitySet s by testing for their existence in the cache,
inspecting the Boolean EntityName Reference.IsLoaded or EntitySet .IsLoaded property value and
invoking the corresponding Load() method if the test returns false . The following snippets illustrate
deferred loading code for Northwind Order entities:
C# 3.0
txtQuery = “SELECT VALUE o FROM NorthwindEntities.Orders AS o “ +
“WHERE o.ShipCountry = ‘Brazil’; “
using (NorthwindEntities ocNwind = new NorthwindEntities(“name=NorthwindEntities”))
{
ObjectQuery < Order > orderQuery;
orderQuery = new ObjectQuery < Order > (txtQuery, ocNwind,
MergeOption.NoTracking)
foreach (Order order in orderQuery)
{
// Defer-load each EntityRef and EntityCollection
if (!order.CustomerReference.IsLoaded)
order.CustomerReference.Load(MergeOption.NoTracking);
if (!order.EmployeeReference.IsLoaded)
order.EmployeeReference.Load(MergeOption.NoTracking);
if (!order.ShipperReference.IsLoaded)
order.ShipperReference.Load(MergeOption.NoTracking);
if (!order.Order_Details.IsLoaded)
order.Order_Details.Load(MergeOption.NoTracking);
}
}
Deferred loading generates and executes the following simple SQL statement to return all
top - level objects:
T - SQL
[Extent1].[OrderID] AS [OrderID],
[Extent1].[OrderDate] AS [OrderDate],
[Extent1].[RequiredDate] AS [RequiredDate],
[Extent1].[ShippedDate] AS [ShippedDate],
[Extent1].[Freight] AS [Freight],
[Extent1].[ShipName] AS [ShipName],
[Extent1].[ShipAddress] AS [ShipAddress],
[Extent1].[ShipCity] AS [ShipCity],
[Extent1].[ShipRegion] AS [ShipRegion],
[Extent1].[ShipPostalCode] AS [ShipPostalCode],
[Extent1].[ShipCountry] AS [ShipCountry]
FROM [dbo].[Orders] AS [Extent1]
WHERE [Extent1].[ShipCountry] = ‘Brazil’
ORDER BY [Extent1].[OrderID] DESC
The query also generates and executes up to four additional T - SQL statements per parent entity to
return the associated Customer , Employee , and Shipper entities, and the Order_Details EntitySet s.
The query generates 21 T - SQL queries if object tracking is off ( MergeOption.NoTracking ) and 16 if
object tracking is on (any other MergeOption specified). Object tracking tests for the existence of
the object in the cache before executing a SQL statement to retrieve it.
Eager Loading with Include() Operators
The Include( EntityRef ) or Include( EntityCollection ) operator returns entity references or
collections associated with the query ’ s parent EntitySet . These operators can be chained to return
multiple references, multiple collections or both from a single query, as in the following example:
C# 3.0
txtQuery = “SELECT VALUE o FROM NorthwindEntities.Orders AS o “ +
“WHERE o.ShipCountry = ‘Brazil’; “
using (NorthwindEntities ocNwind = new NorthwindEntities(“name=NorthwindEntities”))
{
ObjectQuery < Order > orderQuery;
// Eager-load each EntityRef and EntityCollection
orderQuery = new ObjectQuery < Order > (txtQuery.Text, ocNwind,
MergeOption.NoTracking).Include(“Order_Details”).Include(“Customer”)
.Include(“Employee”).Include(“Shipper”);
foreach (Order order in orderQuery)
{
// Tests for loaded references and collection
if (!order.CustomerReference.IsLoaded)
throw new Exception(“Customer Entity isn’t loaded.”);
if (!order.EmployeeReference.IsLoaded)
throw new Exception(“Employee Entity isn’t loaded.”);
if (!order.ShipperReference.IsLoaded)
throw new Exception(“Shipper Entity isn’t loaded.”);
if (!order.Order_Details.IsLoaded)
throw new Exception(“Order_Details EntitySet isn’t loaded.”);
}
}
Despite the size and complexity of the preceding T - SQL query, it executes about 10 percent faster than
the preceding section ’ s 16 queries for deferred loading. As a rule eager loading with ObjectQuery.
Include() operators will outperform deferred loading with the EntityType .Load() method, unless
you must filter, order, or filter and order an associated EntityCollection .

No comments:

Post a Comment