4

I'm currenlty working on a provider hosted app that is hosted in Azure. In this app I need information with multiple lists in multiple sites, which are all in the same sitecollection.I'm basically looking for something like the SPSiteDataQuery. However for as far as I can see, it is only possible to query one list at a a time with CSOM. This would mean that I have to loop trough all sites and all lists to get my data. Is there any way to overcome this issue?

3 Answers 3

1

The CSOM does not provide a mechanism for querying data across multiple lists that are not associated by a lookup field. In other words, there is no client-side functional equivalent of the SPSiteDataQuery class.

Using LINQ for Objects

When you use the CSOM, you can write LINQ queries against client-side objects, such as lists and Webs, and then use the ClientContext class to submit these queries to the server.

Example:

using (var context = new ClientContext(url))
{
    //context.Credentials = credentials;

    var query = from web in context.Site.RootWeb.Webs
                where web.WebTemplate == "STS"
                select web;

    var result = context.LoadQuery(query);
    context.ExecuteQuery();


    foreach (var web in result)
    {
        var listQuery = from list in web.Lists
                    where list.BaseType == BaseType.DocumentLibrary
                    select list;
        var listresult = context.LoadQuery(listQuery);
        context.ExecuteQuery();

        foreach (var list in listresult)
        {
            Console.WriteLine("Web:{0} List:{1}",web.Title,list.Title);
        }
    }   
}

Search based approach

Search in SharePoint 2013 includes a client object model that enables access to search results for online, on-premises, and mobile development. The Search in SharePoint 2013 CSOM is built on the SharePoint 2013 CSOM.

Example:

using (var context = new ClientContext(url))
{
    var query = new KeywordQuery(context);
    query.QueryText = "ContentType:Document";
    query.RowLimit = 8;
    query.SelectProperties.Add("Title");
    var results = new SearchExecutor(context).ExecuteQuery(query);
    context.ExecuteQuery();
}

Reference: Using the SharePoint 2013 search Query APIs

1
  • 1
    Thanks for your answer.The first approach is what I meant with having to loop through all sites and lists, because I can't skip any sites or lists. The second approach is a good alternative but I don't like the delay of the search engine. I'm on SharePoint online and I don't know when indexing happens.
    – Marlou
    Commented Apr 30, 2014 at 10:58
0

Yes it is possible! I don't know of a CSOM equivalent to SPSiteDataQuery, unless you want to explore the Search capabilities of CSOM.

Below you'll find an example of how to do it. I'm sure there exist a more efficient way of doing this, but this is one way I could think of:

var context = new ClientContext("http://MyMagicalUrl");
var currentWeb = context.Web;

// Get all webs from currentWeb object
context.Load(currentWeb, website => website.Webs);
context.ExecuteQuery();

// Now you can loop through all the webs
foreach (Web web in currentWeb.Webs)
{
    // Remember, only get what you need
    var listCollection = context.Load(web.Lists, lists => lists.Include(list => list.Title,list => list.Id));
    context.ExecuteQuery();

    // Now you can do what you want using the list info.
}
1
  • This is what I meant with looping through all sites and all lists to get the correct listitems.
    – Marlou
    Commented Apr 30, 2014 at 10:50
0

I needed this information in a clientwebpart so I ended up with a setting to limited the sites I need to query and used the normal CSOM method. I still have to execute the query on multiple lists so it is still not optimal, but at least the performance is acceptable. Code looks like this.

string siteToQuery = "Global";
SharePointContext spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
using (ClientContext ctx = spContext.CreateUserClientContextForSPHost())
{ 
    var webQuery = ctx.Site.RootWeb.Webs.Where(i => i.Title == siteToQuery).Include(i => i.Webs);
    var webQueryResult = ctx.LoadQuery(webQuery);
    ctx.ExecuteQuery();

    if (webQueryResult.Count() == 1)
    {
      Web parentWeb = webQueryResult.Single();

      CamlQuery camlQuery = new CamlQuery();
      camlQuery.ViewXml = this.GetQuery();

      foreach (Web web in parentWeb.Webs)
      {
        List list = web.Lists.GetByTitle("Pages");       

        Microsoft.SharePoint.Client.ListItemCollection items = list.GetItems(camlQuery);
        ctx.Load(items);
        ctx.ExecuteQuery();

        foreach (var item in items)
        {
          //do stuff
        }
      }
    }
}
2
  • Sharing some of that code, to show your solution, would be preferable Commented May 6, 2014 at 11:42
  • I added some of the code :)
    – Marlou
    Commented May 6, 2014 at 11:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.