Mindscape
  • Register
  • Login
  • YOUR CART IS EMPTY
home
Software
  • Developers Toolbox
  • LightSpeed
  • Raygun
  • WPF Elements
  • Web Workbench
  • Metro Elements
  • Silverlight Elements
  • NHibernate Designer
  • Phone Elements
  • WPF Diagrams
  • Simple DB management
  • Visual Tools for SharePoint
Downloads
Store
  • Buy online
  • Purchase order
  • Volume discounts
  • Reseller
  • Software license
  • Contact sales
Blog
Support
About
  • About Us
  • Contact
  • Testimonials
rss
twitter
facebook
Performance and Tuning Controlling How Entities Load Controlling How Entity Data Loads Intercepting Queries Miscellaneous Performance and Tuning Improvements Understanding Named Aggregates Bulk Updates and Deletes Batching Caching Database Hints Measuring Performance

Controlling How Entities Load

By default, LightSpeed loads entities on demand.  That is, if an entity has an association to another entity or a collection of other entities, the association is loaded the first time an application accesses it.  This requires another query to the database, to retrieve the associated entity or the members of the collection.  (Once the association is loaded, LightSpeed remembers that it’s loaded and doesn’t perform another database query.)  For example:

var order = unitOfWork.FindById<Order>(1); // queries the database for an Order
var reference = order.Reference; // scalar property, no database query
var customer = order.Customer; // queries the database for a Customer
var customerName = order.Customer.Name; // customer is loaded, no database query
var lines = order.Lines; // queries the database for OrderLines
var line0value = order.Lines[0].Value // line is loaded, no database query

This is a safe, conservative strategy which avoids superfluous loads.  It is referred to as lazy loading because it lazily doesn’t do any work it doesn’t need to.

However, when a unit of work needs a number of related entities, it can be imperfectly efficient.  In the code fragment above, LightSpeed issued three database queries.  If we knew ahead of time that the application was going to need the Customer entity and the Lines collection, it would have been more performant to perform all three queries in a single go.

The problem gets worse when dealing with collections of entities.  For example:

var overdues = unitOfWork.Orders.Where(o => o.DueDate < today);
foreach (var o in overdues) // queries the database for Orders
{
  var customer = o.Customer; // queries the database for a Customer
  Console.WriteLine("Order {0} for customer {1} is overdue", o.Reference, customer.Name);
}

This code fragment results in one query for the orders, then, for each order, another query for the customer.  If the first query returned 1000 orders, then we would do 1000 queries for customers – a total of 1001 queries.  This problem is called the N+1 problem because it means you need N+1 queries to process N objects.

LightSpeed makes it easy to avoid these problems using eager loading.

Eager Loading

Eager loading means loading associated entities before they are needed.  In LightSpeed, eager loading specifically means loading associated entities using the same database query as the source entity, avoiding an extra round trip.  Here is how our N+1 code fragment works with eager loading.

var overdues = unitOfWork.Orders.Where(o => o.DueDate < today);
foreach (var o in overdues) // queries the database for Orders *and* Customers
{
  var customer = o.Customer; // Customer is already loaded, no database query
  Console.WriteLine("Order {0} for customer {1} is overdue", o.Reference, customer.Name);
}

By using eager loading we replace 1001 trips to the database to a single trip!  Of course, that one trip now has to do more work, so you should eager load only when you know you are going to need the associations.

To implement eager loading, select an association that you want to be eager loaded, and:

·         If you want parent entities to eager load their children, set Eager Load Collection to True.

·         If you want child entities to eager load their parents, set Eager Load Backreference to True.

In the example above, because you want the Order entity to eager load its associated Customer, you would select the Order to Customer association and set Eager Load Backreference to True.  If you also wanted the Customer entity to eager load its collection of Orders, you would also set Eager Load Collection to True.  (An association can be eager loaded in both directions.)

For hand-coded associations, you implement eager loading by applying the EagerLoad attribute to the association field:

Implementing eager loading on hand-coded associations

public class Order : Entity<int>
{
  [EagerLoad]
  private readonly EntityHolder<Customer> _customer = new EntityHolder<Customer>();
  [EagerLoad]
  private readonly EntityCollection<Line> _lines = new EntityCollection<Line>();
}

Eager loading cascades, allowing you to load a whole object graph in a single database round-trip.  For example, if Customer.Orders is eager loaded, and Order.Lines is eager loaded, then when you load one or more Customers, LightSpeed will automatically fetch not only the orders for all those customers but also the lines for all those orders.

Fine Grained Control Using Named Aggregates

It often happens that some parts of an application want to eager load an association, but other parts do not.  For example, a page which displays the details of an order knows that it will be displaying the order lines, so would want to eager load the Lines collection.  But a page which displays a list of overdue orders doesn’t need to display the individual order lines, so it doesn’t want to eager load the Lines collection – but it might want to eager load the customers so that it could show the user who each overdue order belonged to.

To support conditionally eager loading an association, LightSpeed uses named aggregates.  ‘Aggregate’ is a term from domain-driven design that refers to a bounded object graph that we need to satisfy a particular application use case.  (In the example above, there were two aggregates.  The order details page was interested in an “order plus lines” aggregate.  The overdue orders page was interested in an “order plus customer” aggregate.)  Named aggregates allow you to name particular object graphs, and tell LightSpeed to eager load different aggregates in different situations.

To specify that an association is part of a named aggregate, select the association arrow, and enter the aggregate name in the Collection Aggregates or Backreference Aggregates box (or both).  An association can be part of multiple named aggregates – separate the aggregate names with semicolons.

For hand-coded associations, specify the AggregateName property on the EagerLoad attribute.  You can specify the attribute multiple times.

Specifying that a hand-coded association is part of a named aggregate

public class Order : Entity<int>
{
  [EagerLoad(AggregateName = "WithAllDetails")]
  private readonly EntityHolder<Customer> _customer = new EntityHolder<Customer>();
  [EagerLoad(AggregateName = "WithAllDetails")]
  [EagerLoad(AggregateName = "WithLines")]
  private readonly EntityCollection<Line> _customer = new EntityCollection<Line>();
}

To eager load a particular aggregate using LINQ, specify it in your query using the WithAggregate() method:

Eager loading a named aggregate using LINQ

// Loads orders and associated lines, but not associated customers
var orders = unitOfWork.Orders
                       .Where(o => o.CustomerId == customerId)
                       .WithAggregate("WithLines")
                       .ToList();

In LightSpeed 5 a new feature was added where if a model defines named aggregates, constants based on their names are emitted. This allows you to write code such as WithAggregate(StoreAggregates.WithProductInfo), so you don’t have to specify the named aggregate as a string.

To eager load a particular aggregate using query objects, specify it in using the Query.AggregateName property:

Eager loading a named aggregate using query objects

// Loads orders and associated lines, but not associated customers
Query query = new Query(Entity.Attribute("CustomerId" == customerId))
{
  AggregateName = "WithLines"
};
var orders = unitOfWork.Find<Order>(query);

In both of the above samples, changing “WithLines” to “WithAllDetails” would eager load both the lines and the customers.  Omitting the aggregate would mean both the lines and the customers were lazy loaded.

The aggregate name is an attribute of a query, and affects all associations in the aggregate, not just the associations on the starting object.  For example, if both Customer.Orders and Order.Lines are marked with the “WithAllDetails” aggregate, then loading a Customer with the WithAllDetails aggregate will load the customer’s orders, and all the lines of those orders.  This allows you to load deep object graphs in a single database access if required.

Data Products

  • LightSpeed ORM
  • NHibernate Designer
  • SimpleDB Tools
  • SharePoint Tools

DevOp Tools

  • Raygun

Visual Controls

  • WPF Elements
  • WPF Diagrams
  • Silverlight Elements
  • Phone Elements

Popular Products

  • Web Workbench

    Modern web development for Visual Studio!

  • Mindscape Megapack

    All Mindscape products for one awesome price!

Quick Links

  • Forums
  • Blog
  • Register
  • Login
  • Contact us
  • Twitter
  • Facebook
  • Google+
  • YouTube
  • Linkedin
  • Rss

© Mindscape 2025. Mindscape is a registered trademark of Mindscape Limited.

  • Terms
  • Privacy