Silverlight + SharePoint + CAML - best practices

I was reviewing http://microsoftpdc.com/Sessions/PR07 regarding SharePoint client object model tonight, in consideration of how the client object model should be used with Silverlight to build Silverlight SharePoint solutions.

I really liked slide 20, but I think it needs a bit more expanding:

  • Use .Where method to:
    • Filter down items retrieved in a collection
  • Use .Include method to:
    • Explicitly select properties or child objects to retrieve
    • You own specifying what you want!
    • (use .IncludeWithDefaultProperties for default + custom properties)
  • Use .Take method to:
    • Restrict overall number of items retrieved

 

The object model provides (through LINQ query), these three ways of filtering down the objects that you want to return from SharePoint. 

There's a little bit more that wasn't mentioned - the gem (or curse, if you hate everything related to CAML…) that is

var query = new CamlQuery();
ListItemCollection items = list.GetItems(query);

 

Yes, CAML is far from dead.  And LINQ is not the answer to everything.

The basic issue is that the LINQ syntax is converted into CAML to be passed to SharePoint to execute on the server.  In particular:

  • .Include - dictates the View.Fields that are returned from the service call

WARNING

  • .Take
  • .Where - these two may seem intuitive enough, but actually they are hidden pitfalls here.  The reason is that these parts of the LINQ statement are not translated to CAML.  So you are actually performing these operations on the client side, using essentially LINQ on an unfiltered objects collection. 

Bad performance, and quite possibly bad logic!

If you are really after paging behaviour - SharePoint 2010 has this built into the object model.  A skip and a take is done via:

CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml =
                @"<View>
                    <ViewFields>
                      <FieldRef Name='Title'/>
                      <FieldRef Name='Category'/>
                      <FieldRef Name='Estimate'/>
                    </ViewFields>
                    <RowLimit>10</RowLimit>
                  </View>";
camlQuery.ListItemCollectionPosition = itemPosition; 

Skip is done via paging - see CamlQuery.ListItemCollectionPosition property.
Take is done via CAML <RowLimit>, or alternatively, you can do this via CamlQuery.RowLimit property.

I'll throw in one more, in CAML you can additionally perform Order By - this is one additional area where the order will affect the records returned by the query significantly - especially if you are using paging on top.

 

Guidance

In Silverlight, you should never query ListItems without some safeguards around the Query's RowLimit, as well as possibly handle paging.  On the server side, SharePoint will impose a limit of (default) 2000 items per query.

See more references here

I once read that CAML is compared to the butcher knife, and LINQ is the pocket carving knife (sorry forgot which blog I read this on - let me know).  I agree whole-heartedly: both are tools to control the slice of data you want from SharePoint, but you must keep performance in mind!