Training



Turbocharge Your Data Grid with a Span Query Level 200
DevForce Express
Mar 26, 2007

New users of DevForce sometimes experience what they consider poor performance in the loading of data for datagrids. There's a simple and profoundly effective way to rocket those data loads up to warp speed, and you've already guessed its essence from the title of this Tech Tip. But before we give you the details, it's important that you understand a little bit about how DevForce retrieves data for related objects, and why.

Suppose you need to fill a datagrid with a collection of Orders - lots of Orders. You instantiate a DevForce EntityList(Of T), mOrders, to hold the Orders; and a .NET BindingSource, mOrdersBindingSource, to keep the position pointer in that list. You link the two as follows:

 

C#:

mOrdersBindingSource.DataSource = mOrders;
  


VB.NET:

mOrdersBindingSource.DataSource = mOrders

You use a DevForce DataGridViewBindingManager for a .NET DataGridView grid (or the equivalent BindingManager for a Developers Express or Infragistics grid), and configure it to receive its data from the BindingSource:

 

C#:

mOrdersDataGridViewBindingManager.BindingSource = mOrdersBindingSource;
  

 

VB.NET:

mOrdersDataGridViewBindingManager.BindingSource = mOrdersBindingSource
  

You then retrieve the needed Orders into an EntityList as follows:

 

C#:

mOrders.ReplaceRange(MyPersistenceManager.GetEntities(Of Order)());
  

 

VB.NET:

mOrders.ReplaceRange(MyPersistenceManager.GetEntities(Of Order)())
  

So far so good...but at runtime, your Orders grid seems to take longer than it should to fill with data. What's the problem?

Almost invariably, the source of the problem will be that the Order object has relation properties -- like, say, Customer and Shipper -- that connect it to related entities; and that those related objects are referenced in cells of the grid rows. Now, relation properties are hardly a problem in and of themselves: in fact, they're quite wonderful to work with, making it extremely easy and intuitive to navigate relationships in your code, with statements like this:

 

C#:

MyOrder.Customer.Agent.Contact.FullName;
  

 

VB.NET:

MyOrder.Customer.Agent.Contact.FullName
  

But DevForce only loads the data for relation properties on demand by the client application. When filling a data grid, that demand comes one Order at a time. As each Order row is loaded, it says, "And by the way, can you also get me the Customer that placed me and the Shipper that will ship me?" If you're bringing a thousand Orders into the grid, that's 2000 separate additional queries to get those related Customers and Shippers!

For many of the things your application will do, this default behavior of "Just-In-Time" data loading is perfect. It keeps performance high, and unnecessary data retrievals to a minimum. DevForce doesn't know, when you call GetEntities(), how you're going to use the retrieved entities, or which of the objects related to the retrieved entities, if any, you're going to need. So it only loads what you specifically asked for, and waits to see what you will want to do next. A datagrid, however, imposes special demands by requiring the UI to display a great many objects at once. In this circumstance, leaving DevForce in the dark about what related objects you are going to need results in poor performance.

Span Queries to the Rescue

Enter the span query:

 

C#:

EntityList mOrders = new EntityList();
...
IdeaBlade.Persistence.EntityQuery anOrderSpanQuery =
  new IdeaBlade.Persistence.EntityQuery(typeof(Order));
anOrderSpanQuery.AddSpan(EntityRelations.Order_Customer,
  EntityRelations.Customer_Agent,
  EntityRelations.Agent_Contact);
anOrderSpanQuery.AddSpan(EntityRelations.Order_Shipper);
mOrders.ReplaceRange(mPersMgr.GetEntities(anOrderSpanQuery));
  

 

VB.NET:

Dim mOrders As New EntityList(Of Order)
...
Dim anOrderSpanQuery As New IdeaBlade.Persistence.EntityQuery(GetType(Order)) anOrderSpanQuery.AddSpan(EntityRelations.Order_Customer, _
  EntityRelations.Customer_Agent, _
  EntityRelations.Agent_Contact)
anOrderSpanQuery.AddSpan(EntityRelations.Order_Shipper)
mOrders.ReplaceRange(mPersMgr.GetEntities(Of order)(anOrderSpanQuery))
  

Like an ordinary query, the above query ultimately returns a list of pointers to objects of a single type (in this case, Order) in the DevForce local cache. But in the process, it makes sure that not only those Orders, but also the related Customer, Agent, Contact, and Shipper objects, are represented in that cache. If they've already been retrieved by some prior data request, GetEntities() simply finds them in the cache; if not, it goes out to the back-end datasource for them.

Now what happens when it's time to fill the datagrid? DevForce still must find the Contact object referenced in the statement:

 

C#:

MyOrder.Customer.Agent.Contact.FullName;

  

VB.NET:

MyOrder.Customer.Agent.Contact.FullName
  

But no trips to the back-end datasource are required. The needed Customer object is in the cache, as are the related Agent and Contact objects. DevForce finds the targeted Contact at local bus speed (fast!!!). The grid fills quickly.

Best of Both Worlds

Now you have everything: Just-In-Time data loading as the default, so your application doesn't waste time retrieving data it doesn't need; and the ability to anticipate the data it will need and pre-fetch it in big chunks. Have your cake and eat it, too!

If your grid is going to need to display a really large number of records, you might also want to consider using a Paged Query to retrieve the data a specified number of rows at a time. Such paged queries, like ordinary queries, can also be defined with spans so that you retrieve, say, not only the next 100 Orders, but also the Customers, Agents, and Contacts related to those Orders. And if you really want to tune for performance, you can do all of the above in conjunction with one or more Asynchronous Queries that retrieve data on background threads while your end user is occupied with other business in the user interface. Your days of slow-loading datagrids are over!


All Tech Tips