LINQing to the Live Framework (or “CreateQuery vs Entries”)

There are two possible different ways to query in the Live Framework if you are using the .NET or Silverlight Toolkits. They look very similar but behave differently.

Let’s say we want to find all the Mesh Objects which start with the letter ‘M’ and generate a string of all of their titles.  We might write something like the following:

 Mesh mesh = LiveFXHelper.Endpoint.Mesh; 
var query1 = from meshObject in mesh.MeshObjects.Entries 
    where meshObject.Resource.Title.StartsWith("M") 
    select meshObject; 
StringBuilder sb = new StringBuilder(); 
foreach (var o in query1) 
{ 
    sb.AppendLine(o.Resource.Title); 
}

 

Looking at Fiddler, this code generates no network traffic. It loads the data from the local in-process cache of the data. Any subsequent requests will continue to be processed by the local data. This happens because the client makes the following two HTTP requests to the cloud (local or remote) immediately upon startup:

GET /?$expand=Mesh,Profiles,Contacts HTTP/1.1

GET /V0.1/Mesh/?$expand=Devices,News,MeshObjects HTTP/1.1

These requests return the top level Mesh, Profiles, and Contacts in the user’s data and then the list of MeshObjects, Devices, and News within the user’s Mesh. These requests happen once and the data is then used to service any normal LINQ queries in the object model. (Note: a similar thing happens for objects lower down the hierarchy but they will need to be loaded at least once from the LOE via the Load() method) The .NET toolkit libraries will also poll the LOE periodically to update the local copies of the data.

If we now change the highlighted portion to use the CreateQuery method instead, it looks like this:

 Mesh mesh = LiveFXHelper.Endpoint.Mesh; 
var query1 = from meshObject in mesh.CreateQuery<MeshObject>() 
    where meshObject.Resource.Title.StartsWith("M") 
    select meshObject; 
StringBuilder sb = new StringBuilder(); 
foreach (var o in query1) 
{ 
    sb.AppendLine(o.Resource.Title); 
}

 

This changes the behavior dramatically. We suddenly see requests to the LOE which look like this:

GET /V0.1/Mesh/MeshObjects?$filter=startswith(Title,'M') HTTP/1.1

This request happens every subsequent time we do a query with the CreateQuery() method. The CreateQuery() method provides a way for the developer to proxy portions of the LINQ query to the server. The .NET toolkit classes will break the query down and construct a GET request with appropriate url parameters in order to do much of the work on the server in order to optimize the network traffic. Notice the $filter parameter which passes the WHERE clause to the server.

This is an important behavior that the developer must be aware of because changes to the LOE data (whether local LOE or cloud LOE) will not be seen immediately in the first type of query but will in the second. This has the potential to confuse the application if the developer mixes one type of query with the other.

In general it is best to always query by using the CreateQuery() method. This will provide you with the current version of the LOE data. You will offload some of the filter processing to the server. You do not need to worry about whether you have loaded the entries from the LOE before, and if you are connecting to the Local LOE you will not incur any performance penalty because it all happens on the same machine.