Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / productivity / SharePoint

Support for IN CAML operation in Camlex

4.00/5 (1 vote)
19 Nov 2013Ms-PL2 min read 15K  
Describes support for IN CAML operation in Camlex open source library for Sharepoint developers

Introduction

Camlex.Net is free open source project for Sharepoint developers which simplifies creation of CAML queries (project site is here). You may read my previous articles about it on Codeproject here. In this article I will describe new feature added with version 3.5 (in client object model version - with 1.3): support for IN operation.

MSDN article says the following about IN operation:

"Specifies whether the value of a list item for the field specified by the FieldRef element is equal to one of the values specified by the Values element " 

E.g. if we need to get all list items which have integer Count field in range 0..9 we can use the following query:

XML
<Where>
  <In>
    <FieldRef Name="Count" />
    <Values>
      <Value Type="Integer">0</Value>
      <Value Type="Integer">1</Value>
      <Value Type="Integer">2</Value>
      <Value Type="Integer">3</Value>
      <Value Type="Integer">4</Value>
      <Value Type="Integer">5</Value>
      <Value Type="Integer">6</Value>
      <Value Type="Integer">7</Value>
      <Value Type="Integer">8</Value>
      <Value Type="Integer">9</Value>
    </Values>
  </In>
</Where>

It was possible to combine multiple Eq operations using Or and get the same result. And with Camlex it was quite easy to do it using single line of code (for better reading I put it to 3 lines):

C#
 string caml = Camlex.Query().WhereAny(
    Enumerable.Range(0, 9).Select<int, Expression<Func<SPListItem, bool>>>(
        i => x => (int) x["Count"] == i)).ToString();

But let’s see the resulting CAML of the above code:

XML
<Where>
  <Or>
    <Or>
      <Or>
        <Or>
          <Or>
            <Or>
              <Or>
                <Or>
                  <Eq>
                    <FieldRef Name="Count" />
                    <Value Type="Integer">0</Value>
                  </Eq>
                  <Eq>
                    <FieldRef Name="Count" />
                    <Value Type="Integer">1</Value>
                  </Eq>
                </Or>
                <Eq>
                  <FieldRef Name="Count" />
                  <Value Type="Integer">2</Value>
                </Eq>
              </Or>
              <Eq>
                <FieldRef Name="Count" />
                <Value Type="Integer">3</Value>
              </Eq>
            </Or>
            <Eq>
              <FieldRef Name="Count" />
              <Value Type="Integer">4</Value>
            </Eq>
          </Or>
          <Eq>
            <FieldRef Name="Count" />
            <Value Type="Integer">5</Value>
          </Eq>
        </Or>
        <Eq>
          <FieldRef Name="Count" />
          <Value Type="Integer">6</Value>
        </Eq>
      </Or>
      <Eq>
        <FieldRef Name="Count" />
        <Value Type="Integer">7</Value>
      </Eq>
    </Or>
    <Eq>
      <FieldRef Name="Count" />
      <Value Type="Integer">8</Value>
    </Eq>
  </Or>
</Where>

Comparing with 1st example, it looks not very nice. If it doesn’t matter for you, you still can use OR syntax. However now it is possible to write simpler expression which will produce IN syntax:

C#
string caml = Camlex.Query().Where(x => Enumerable.Range(0, 9).Contains((int)x["Count"])).ToString();

It will produce CAML which we already saw:

XML
<Where>
  <In>
    <FieldRef Name="Count" />
    <Values>
      <Value Type="Integer">0</Value>
      <Value Type="Integer">1</Value>
      <Value Type="Integer">2</Value>
      <Value Type="Integer">3</Value>
      <Value Type="Integer">4</Value>
      <Value Type="Integer">5</Value>
      <Value Type="Integer">6</Value>
      <Value Type="Integer">7</Value>
      <Value Type="Integer">8</Value>
    </Values>
  </In>
</Where>

For those who worked with NHibernate or Linq2Sql this syntax won’t be new: these ORM frameworks use the same syntax for generating of SQL queries with IN operator. I intentionally showed example with dynamically populated array (Enumerable.Range(0, 9)): code supports any expression which produces IEnumerable:

C#
var caml = Camlex.Query().Where(x => getArray().Contains((int)x["Count"])).ToString();
...
List<int> getArray()
{
    var list = new List<int>();
    for (int i = 0; i < 10; i++)
    {
        list.Add(i);
    }
    return list;
}

(Do you see the difference between the last example which function which returns List<int>, and previous example, which uses IEnumerable? Class List<T> has own Contains method, while for IEnumerable<int> from first example Linq Contains extension method was used. As you can see Camlex may work with both of them. Note that if you use Linq you should add “using System.Linq;” to your file).

I.e. basic syntax is the following:

C#
var caml = Camlex.Query().Where(x => enumerable.Contains((Type)x["FieldTitle"])).ToString();

Of course you may write array with constants:

C#
string c = Camlex.Query().Where(x => new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    .Contains((int) x["Count"])).ToString();

Also it will work with any type supported for Value element:

C#
string c = Camlex.Query().Where(x => new[]
    {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
        .Contains((string) x["Title"])).ToString();

It will produce the following result:

XML
<Where>
  <In>
    <FieldRef Name="Title" />
    <Values>
      <Value Type="Text">zero</Value>
      <Value Type="Text">one</Value>
      <Value Type="Text">two</Value>
      <Value Type="Text">three</Value>
      <Value Type="Text">four</Value>
      <Value Type="Text">five</Value>
      <Value Type="Text">six</Value>
      <Value Type="Text">seven</Value>
      <Value Type="Text">eight</Value>
      <Value Type="Text">nine</Value>
    </Values>
  </In>
</Where>

Now it uses Text type in Value elements.

That was only half of the story. If you follow the Camlex, you probably know that starting with version 3.0 it became bidirectional (I wrote about it here: Camlex.NET became bidirectional and goes online. Version 3.0 is released). So all conversions are added with 2 directions: from expression to CAML and from CAML to expression:

C#
var xml =
    "<Query>" +
    "  <Where>" +
    "    <In>" +
    "      <FieldRef Name=\"Title\" />" +
    "      <Values>" +
    "        <Value Type=\"Text\">zero</Value>" +
    "        <Value Type=\"Text\">one</Value>" +
    "        <Value Type=\"Text\">two</Value>" +
    "        <Value Type=\"Text\">three</Value>" +
    "        <Value Type=\"Text\">four</Value>" +
    "        <Value Type=\"Text\">five</Value>" +
    "        <Value Type=\"Text\">six</Value>" +
    "        <Value Type=\"Text\">seven</Value>" +
    "        <Value Type=\"Text\">eight</Value>" +
    "        <Value Type=\"Text\">nine</Value>" +
    "      </Values>" +
    "    </In>" +
    "  </Where>" +
    "</Query>";
 
var expr = Camlex.QueryFromString(xml).ToExpression();

Applications of that feature:

1. on http://camlex-online.org/ add xml shown below to the textarea and click Convert to C#. It will show you how this query will be produced by Camlex:

C#
Camlex.Query().Where(x => new[] {
    "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }
        .Contains((string)x["Title"]))

2. it is possible to add more conditions to the existing IN query which is stored as xml, or add IN query to existing query:

C#
var xml =
    "<Query>" +
    "  <Where>" +
    "    <In>" +
    "      <FieldRef Name=\"Title\" />" +
    "      <Values>" +
    "        <Value Type=\"Text\">one</Value>" +
    "        <Value Type=\"Text\">two</Value>" +
    "      </Values>" +
    "    </In>" +
    "  </Where>" +
    "</Query>";
 
string caml = Camlex.Query().WhereAll(xml, x => (int)x["Count"] == 1).ToString();

will produce:

XML
<Where>
  <And>
    <Eq>
      <FieldRef Name="Count" />
      <Value Type="Integer">1</Value>
    </Eq>
    <In>
      <FieldRef Name="Title" />
      <Values>
        <Value Type="Text">one</Value>
        <Value Type="Text">two</Value>
      </Values>
    </In>
  </And>
</Where>

I.e. Camlex may combine several string queries using Or and And, or even mix string query with expression as shown above. This feature was added in previous releases.  

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)