Linq to SharePoint. Part 2

Part 1. First()/FirstOrDefault(), T-SQL IN, Path
Part 2. Count(), Take(), Skip(), JOIN, ObjectTracking
Part 3. Anonymous access, Resolve list by URL
Part 4. Dynamic LINQ, Convert SPListItem to data context object
Part 5. Choice and MultiChoice fields

For demonstration i've created a simple project which contains four content types (Employee, Department, Branch and Company), fields for them, lists and classes representing these entities:

Tracing

First of all for testing building of CAML queries it's necessary a tracer. Here is one used by myself:

  1. public class ZhukBlogTracer : TextWriter
  2. {
  3.   public override Encoding Encoding
  4.   {
  5.     get { return Encoding.UTF8; }
  6.   }
  7.  
  8.   public override void WriteLine(string value)
  9.   {
  10.     Debug.WriteLine(string.Empty);
  11.     Debug.WriteLine("---------------------------------------------------------");
  12.     Debug.WriteLine(value);
  13.     Debug.WriteLine("---------------------------------------------------------");
  14.  
  15.   }
  16.  
  17.   public override void Flush()
  18.   {
  19.     Debug.Flush();
  20.   }
  21. }

Is just writes CAML query to the Output window of Visual Studio. It's enough for testing. To use it's enough to set Log property of data context to instance of ZhukBlogTracer class.

Count()

Linq to SharePoint knows nothing about this extension method and so it'll retrieve all items from list and then Count method will be executed. Bu it'll be Linq to Object, not Linq to SharePoint. If you need to count then number of items it must be limit selected fields. All we need is just ID field of item:

  1. var branchQnt = ctx.Branches
  2.   .Where(b => b.City != "Moscow")
  3.   .Count(); // LINQ to Objects !
  4. var branchQntQuick = ctx.Branches
  5.   .Where(b => b.City != "Moscow")
  6.   .Select(b => b.Id) // ViewFields
  7.   .Count();

Following CAML query will be built as a result of it:

  1. <View>
  2.  <Query>
  3.   <Where>
  4.    <And>
  5.     <BeginsWith>
  6.      <FieldRef Name="ContentTypeId" />
  7.      <Value Type="ContentTypeId">0x01007087DA17F20149E3A4602E517E6E8EEF</Value>
  8.     </BeginsWith>
  9.     <Neq>
  10.      <FieldRef Name="City" />
  11.      <Value Type="Text">Moscow</Value>
  12.     </Neq>
  13.    </And>
  14.   </Where>
  15.  </Query>
  16.  <ViewFields>
  17.   <FieldRef Name="ID" />
  18.  </ViewFields>
  19.  <RowLimit Paged="TRUE">2147483647</RowLimit>
  20. </View>

Take(n), Skip(n)

It's not a trivial case too. CAML-query has RowLimit parameter, which limits count of items and following code sets RowLimit property to 10:

  1. var branchTake = ctx.Branches
  2.   .Where(b => b.City != "Moscow")
  3.   .Take(10)
  4.   .Count();

As for Skip method, Linq to SharePoint retrieves all items before executing of it. The usual sequential call of Skip and Take mothods - it's not Linq to SharePoint:

  1. var branchSkipTake = ctx.Branches
  2.   .Where(b => b.City != "Moscow")
  3.   .Skip(10) // LINQ to Objects !
  4.   .Take(10); // LINQ to Objects !

If paging is necessary on a project the only way to do this is replace Skip method with Take one. If page size is 10 items retriving for N'th page is equal 10*N.

  1. // pageIndex - index of the current page
  2. // pageSize - page size
  3. var branchPaged = ctx.Branches
  4.   .Where(b => b.City != "Moscow")
  5.   .Take((pageIndex + 1) * pageSize)
  6.   .Skip(pageIndex * pageSize); // LINQ to Objects !

JOINs

Join of lists appering in SharePoint 2010 based on EntityRef properties of objects representing these lists (or document libraries). There is no way to use this functionality be calling Join extension method. In addition to this limitation there is another one: only Many-to-One relationships are supported for parent-child queries. Here is an example:

  1. var bigJoin = ctx.Employees
  2.   .Where(x => x.Department.Title.Contains("IT"))
  3.   .Where(x => x.Title.Contains("Zhukov"))
  4.   .ToList();

And here is a long-awaited JOIN in the CAML query:

  1. <View>
  2.  <Query>
  3.   <Where>
  4.    <And>
  5.     <And>
  6.      <BeginsWith>
  7.       <FieldRef Name="ContentTypeId" />
  8.       <Value Type="ContentTypeId">0x010078B0DD38574940478CF9E129FCD65E9B</Value>
  9.      </BeginsWith>
  10.      <Contains>
  11.       <FieldRef Name="DepartmentTitle" />
  12.       <Value Type="Lookup">IT</Value>
  13.      </Contains>
  14.     </And>
  15.     <Contains>
  16.      <FieldRef Name="Title" />
  17.      <Value Type="Text">Zhukov</Value>
  18.     </Contains>
  19.    </And>
  20.   </Where>
  21.  </Query>
  22.  <ViewFields>
  23.   <FieldRef Name="CellPhone" />
  24.   <FieldRef Name="AccessLevel" />
  25.   <FieldRef Name="Manager" />
  26.   <FieldRef Name="Department" />
  27.   <FieldRef Name="ID" />
  28.   <FieldRef Name="owshiddenversion" />
  29.   <FieldRef Name="FileDirRef" />
  30.   <FieldRef Name="Title" />
  31.   <FieldRef Name="Author" />
  32.   <FieldRef Name="Editor" />
  33.  </ViewFields>
  34.  <ProjectedFields>
  35.   <Field Name="DepartmentTitle" Type="Lookup" List="Department" ShowField="Title" />
  36.  </ProjectedFields>
  37.  <Joins>
  38.   <Join Type="LEFT" ListAlias="Department">
  39.    <!--List Name: Departments-->
  40.    <Eq>
  41.     <FieldRef Name="Department" RefType="ID" />
  42.     <FieldRef List="Department" Name="ID" />
  43.    </Eq>
  44.   </Join>
  45.  </Joins>
  46.  <RowLimit Paged="TRUE">2147483647</RowLimit>
  47. </View>

ObjectTrackingEnabled

The last thing is a trick with ObjectTrackingEnabled property of a data context. This boolean proerty shows that tracking of objects is enabled or not. In the case of using Linq to SharePoint in readonly mode set this property to false for more performance.

Source code is available here.

Vitaly Zhukov

Vitaly Zhukov

Tech Lead, Architect, Developer, Technical Trainer, Microsoft MVP. Over 20 years of experience in system integration and software development. I specialize in designing and implementing scalable, high-performance software solutions across various industries.

You May Also Like

Call Dataverse API from SPFx Web Part

Call Dataverse API from SPFx Web Part

Provision Lists and Libraries with SPFx solution

Provision Lists and Libraries with SPFx solution

SharePoint. Drag-and-Drop File Uploading

SharePoint. Drag-and-Drop File Uploading

CSOM. Upload document

CSOM. Upload document

SharePoint List REST API. Part 2

SharePoint List REST API. Part 2

SharePoint Framework. Create Angular WebPart

SharePoint Framework. Create Angular WebPart

SharePoint List REST API. Part 1

SharePoint List REST API. Part 1

Project Server. CSOM + Custom Fields

Project Server. CSOM + Custom Fields

SharePoint 2010. Long time operation with updatable status

SharePoint 2010. Long time operation with updatable status

Linq to SharePoint. Cross site collection queries

Linq to SharePoint. Cross site collection queries

SharePoint. Getting Document Icon URL

SharePoint. Getting Document Icon URL

Linq to SharePoint. Repository pattern

Linq to SharePoint. Repository pattern

Linq to SharePoint vs Camlex.NET Performance Comparison

Linq to SharePoint vs Camlex.NET Performance Comparison

Linq to SharePoint. Part 5. Choice and MultiChoice fields

Linq to SharePoint. Part 5. Choice and MultiChoice fields

Linq to SharePoint. Part 4

Linq to SharePoint. Part 4

Linq to SharePoint. Part 3

Linq to SharePoint. Part 3

Linq to Sharepoint. Part 1

Linq to Sharepoint. Part 1