Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Camlex.NET 2.0 for Windows SharePoint Services

0.00/5 (No votes)
7 Apr 2010Ms-PL5 min read 1   120  
Camlex.NET 2.0 brings to Sharepoint developers new opportunities like dynamic filter conditions, search by field ID and others

External Links for Downloads

Introduction

I'm glad to announce that the next version of Camlex.NET project is released. About 2 months ago, I released Camlex_NET. During this time, we received feedback from the community and took into account applied developers' needs when working over the 2.0 version. Few days ago, Camlex.NET 2.0 was released. In this article, I will describe new features and differences from the previous version.

1. Dynamic Filtering Conditions

This is the most exciting feature added in the 2.0 version. In every-day Sharepoint development, we often need to build CAML query based on predefined set of values. E.g. we need to search items which have Ids contained in array {1, 2, 3} (analog of IN operator in SQL), or we need to retrieve all items which contain one of the substrings (or all of them) in their Title { “hello”, “world” }. This was not easy with the classical approach of building CAML queries based on strings. It was also not so easy with Camlex.NET 1.0: I showed an example of how to build a dynamic expression based on set of values and pass it to Camlex in one of the blog posts. Nevertheless it required extra “infrastructure” work from developer. By infrastructure, I mean those works which are not related directly with the business task – to retrieve items which match some conditions. In version 2.0, we addressed this issue and added 2 additional methods in IQuery interface WhereAll and WhereAny (by analogy with All and Any methods in LINQ):

C#
public interface IQuery
{
    IQuery Where(Expression<Func<SPListItem, bool>> expr);
    IQuery WhereAll(IEnumerable<Expression<Func<SPListItem, bool>>> expressions);
    IQuery WhereAny(IEnumerable<Expression<Func<SPListItem, bool>>> expressions);
    ...
}

Method Where exists from 1.0 version. I showed it here in order to compare signatures of new methods with the old one. The main difference is that WhereAll and WhereAny methods receive list of lambda expressions (or more accurate – IEnumerable) in contrast to Where method which receives a single lambda expression.

So what do these methods do? As I said, they were named by analogy with LINQ methods. And by analogy with them, WhereAll method constructs CAML query for retrieving those items which satisfy all conditions specified in the argument. In other words, WhereAll method constructs CAML query using <And> logical join (see And element). WhereAny method returns CAML query which can be used to retrieve items which satisfy at least one of the specified conditions – it uses <Or> logical join (see Or element).

Let's see examples. Suppose that we need to retrieve all items which contain at least one of the values {“hello”, “greeting”, “hi”} in Title field, i.e., we need to use the following CAML query:

XML
<Where>
  <Or>
    <Or>
      <Contains>
        <FieldRef Name="Title" />
        <Value Type="Text">hello</Value>
      </Contains>
      <Contains>
        <FieldRef Name="Title" />
        <Value Type="Text">greeting</Value>
      </Contains>
    </Or>
    <Contains>
      <FieldRef Name="Title" />
      <Value Type="Text">hi</Value>
    </Contains>
  </Or>
</Where>

That’s how it can be done in Camlex.NET 2.0:

C#
// list of tokens
var tokens = new List<string> { "hello", "greeting", "hi" };
var expressions = new List<Expression<Func<SPListItem, bool>>>();

// create lambda expression for each token in list
foreach (string t in tokens)
{
string token = t;
expressions.Add(x => ((string)x["Title"]).Contains(token));
}

// prepare query
string query = Camlex.Query().WhereAny(expressions).ToString();

So the idea is quite simple – create a list of lambda expressions and pass this list into Camlex. It will join expressions using And or Or joins – so it will have one big expression as a result and pass it in the old Where method which you are familiar with from 1.0 version.

Notice that you can create various expressions – i.e. it is not necessary to create the same expression for each value. You can even provide different argument names in expressions – Camlex doesn't restrict you to have the same argument names for all provided expressions. E.g. we need to select items which have ID = 1 and with Title = “Hello world”:

XML
<Where>
  <And>
    <Eq>
      <FieldRef Name="ID" />
      <Value Type="Integer">1</Value>
    </Eq>
    <Eq>
      <FieldRef Name="Title" />
      <Value Type="Text">Hello world</Value>
    </Eq>
  </And>
</Where>

It can be done using the following code:

C#
var expressions = new List<Expression<Func<SPListItem, bool>>>();
expressions.Add(x => (int)x["ID"] == 1);
expressions.Add(y => (string)y["Title"] == "Hello world");

string query = Camlex.Query().WhereAll(expressions).ToString();

As you can see, Camlex may successfully translate queries with different arguments names “x” and “y”.

2. Search by Field Ids

Camlex 1.0 allowed only to search items using field Title. But often developers use field Id when preparing the CAML query. In Camlex.NET 2.0, it is available now. Let's see how to search items which have Title = “Hello world” using field Id of standard Title field:

XML
<Where>
  <Eq>
    <FieldRef ID="fa564e0f-0c70-4ab9-b863-0177e6ddd247" />
    <Value Type="Text">Hello world</Value>
  </Eq>
</Where>

The following code produces this CAML query:

C#
string query = Camlex.Query().Where(x => 
	(string) x[SPBuiltInFieldId.Title] == "Hello world").ToString();

SPBuiltInFieldId.Title is the OTB property of System.Guid type. You can also provide your own variable of Guid type in the indexer.

One drawback is that with this feature we've lost drawback compatibility with 1.0 version. In the previous version, we used SPItem in all expressions which have only 2 indexers with int and string arguments. We changed SPItem –> SPListItem which has an additional indexer with System.Guid parameter. It became a breaking change in 2.0 version.

3. Search by Lookup id and Lookup Value

In CAML, you can search items by lookup value and lookup id using undocumented LookupId attribute of FieldRef element: see comments to FieldRef Element MSDN article. It is also available in Camlex.NET 2.0. E.g. suppose that there is a “Status” lookup field in some list and we need to retrieve those items which have Status = “Completed”. We can do it either using lookup value:

XML
<Where>
  <Eq>
    <FieldRef Name="Status" />
    <Value Type="Lookup">Completed</Value>
  </Eq>
</Where>

or using lookup id (suppose that lookup item which has Title = “Completed” has ID = 1):

XML
<Where>
  <Eq>
    <FieldRef Name="Status" LookupId="True" />
    <Value Type="Lookup">1</Value>
  </Eq>
</Where>

For this use case in Camlex.NET 2.0, we introduced 2 new types for string-based syntax: DataTypes.LookupId and DataTypes.LookupValue. Previous DataTypes.Lookup have been made internal (this is the 2nd breaking change in 2.0 version). So CAML queries mentioned above can be created using the following code:

C#
// lookup value
string query = Camlex.Query().Where(
x => x["Status"] == (DataTypes.LookupValue)"Completed").ToString();

// lookup id
query = Camlex.Query().Where(
x => x["Status"] == (DataTypes.LookupId)"1").ToString();

4. Support for Native System.Guid Type for Values

One more native type is supported in Camlex.NET 2.0: System.Guid. In the previous version, developers needed to cast variable of Guid type to string in order to specify Guid as value in CAML query ((DataTypes.Guid)val.ToString()). Now you can just pass Guid variable into expression:

C#
var guid = new Guid("a30bcb5a-c614-4dc0-8df0-8741e2aebfd9");
string query = Camlex.Query().Where(x => (Guid)x["UniqueId"] == guid).ToString();

So with Camlex.NET 2.0, you can specify Guid both in indexer and in value.

This was an overview of new features in Camlex.NET 2.0. Hope it will be useful in Sharepoint development and will allow developers to increase their productivity. Thanks to all guys who provide us feedback on Camlex. We appreciate these efforts very much and hope that you will provide us your feedback in the future as well because it will allow us to make Camlex better.

Additional Resources

History

  • 7th April, 2010: Initial post

License

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