Introduction
Camlex.NET (http://camlex.codeplex.com) is a new tool for Sharepoint developers which allows to use lambda expressions and fluent interfaces in order to write CAML queries. It abstracts developers from syntax of CAML queries and helps them to concentrate on business tasks. With Camlex.NET, developers could think about WHAT they need to do, instead of HOW to do it. It also brings the following advantages for Sharepoint developers:
- Compile time checking of expressions
- Natural and intuitive syntax using lambda expressions and fluent interfaces
- Support for native .NET types (
int
, string
s, bool
, DateTime
) and operations (==, !=, >, <, etc.) - Support for Sharepoint-specific data types
- Ability to specify non-constant expressions inside filtering conditions (variables, method calls, etc.)
- Fully customizable resulting query object
In order to start working with Camlex.NET, you should download release package from here and reference Camlex.NET.dll assembly in your project. After that, you can create CAML queries using lambda expressions.
Basic Scenarios
Let's consider some basic scenarios:
Scenario 1. Simple Query
Suppose that you need to select all items which have Status
field set to Completed
(following is the standard syntax of CAML):
<Where>
<Eq>
<FieldRef Name="Status" />
<Value Type="Text">Completed</Value>
</Eq>
</Where>
This query can be made with Camlex using the following syntax:
string caml =
Camlex
.Query()
.Where(x => (string)x["Status"] == "Completed").ToString();
Scenario 2. Query with “and”/”or” conditions
Suppose that you need to select items which have ProductID = 1000
and IsCompleted
set to false
or null
. Syntax of appropriate standard CAML query follows:
<Where>
<And>
<Eq>
<FieldRef Name="ProductID" />
<Value Type="Integer">1000</Value>
</Eq>
<Or>
<Eq>
<FieldRef Name="IsCompleted" />
<Value Type="Boolean">0</Value>
</Eq>
<IsNull>
<FieldRef Name="IsCompleted" />
</IsNull>
</Or>
</And>
</Where>
With the help of Camlex, it could be converted using the following natural syntax:
var caml =
Camlex
.Query()
.Where(x => (int)x["ProductID"] == 1000 &&
((bool)x["IsCompleted"] == false || x["IsCompleted"] == null))
.ToString();
Scenario 3. Query with Non-constant Expressions in lvalue and rvalue
Non-constant expression gives you more control over CAML. Suppose that you need to select items depending on current locale: for English locale, you need to select items which have TitleEng
field set to “eng
”; for non-English locale, you need to select items which have Title
field set to “non-eng
”, i.e.:
Query for English locale:
<Where>
<Eq>
<FieldRef Name="TitleEng" />
<Value Type="Text">eng</Value>
</Eq>
</Where>
Query for non-English locale:
<Where>
<Eq>
<FieldRef Name="Title" />
<Value Type="Text">non-eng</Value>
</Eq>
</Where>
It is not so hard with Camlex:
bool isEng = true;
var caml =
Camlex
.Query()
.Where(x => (string)x[isEng ? "TitleEng" :
"Title"] == (isEng ? "eng" : "non-eng"))
.ToString();
Internal Architecture
Generally Camlex – is translator from lambda expression into CAML:
It receives expression like:
x => (int)x["ID"] == 1
on input and translates it to a valid CAML query. The exact signature of lambda expressions depends on method call of Camlex public
interface. The most important interface in Camlex.NET assembly is IQuery
and its implementation – Query
class:
public interface IQuery
{
IQuery Where(Expression<Func<SPItem, bool>> expr);
IQuery OrderBy(Expression<Func<SPItem, object>> expr);
IQuery OrderBy(Expression<Func<SPItem, object[]>> expr);
IQuery GroupBy(Expression<Func<SPItem, object>> expr);
IQuery GroupBy(Expression<Func<SPItem, object[]>> expr,
bool? collapse, int? groupLimit);
IQuery GroupBy(Expression<Func<SPItem, object>> expr,
bool? collapse, int? groupLimit);
IQuery GroupBy(Expression<Func<SPItem, object>> expr, int? groupLimit);
IQuery GroupBy(Expression<Func<SPItem, object>> expr, bool? collapse);
XElement[] ToCaml(bool includeQueryTag);
string ToString();
string ToString(bool includeQueryTag);
}
As you can see, most methods return itself – so fluent interface calls are available with Camlex:
var caml =
Camlex
.Query()
.Where(x => x["Status"] != null)
.GroupBy(x => x["CreatedBy"])
.ToString();
Also notice that it has ToCaml()
method which returns valid XML in array of XElement
objects. It means that it can be simply customizable – for example, you can use LINQ to XML or classes from System.Xml.Linq
namespace in order to modify resulting query.
Lambda Expressions Syntax
Internally Camlex uses expression trees in order to parse lambda expressions and translate it to CAML. There are 2 types of syntaxes allowed in Camlex (here and below “x” – is a parameter for lambda expression with SPItem
data type defined in Microsoft.Sharepoint.dll):
1. Native syntax:
x => (int)x["ID"] == 1
I.e. you write integer rvalue and cast lvalue
to int
:
2. String based syntax:
x => x["ID"] == (DataTypes.Integer)"1"
Opposite native syntax you write integer value in string representation and cast it to DataTypes.Integer
class (helper class defined in Camlex.NET.dll).
Two examples above are equivalent for Camlex. We introduced 2 types of syntaxes in order to be able to write queries with not only native .NET types (int
, string
, bool
, DateTime
), but also with Sharepoint data types (see MSDN link). You can easily mix these syntaxes and composite them via logical operations (&&, ||) in the same expression.
The following schema shows how Camlex translates lambda expression with native into CAML query:
String
based syntax is very similar except Camlex uses rvalue
cast to DataTypes.Integer
in order to determine type of value and checks that string
representation contains valid value for this type.
What happens if Camlex cannot parse lambda expression? As described above, there are only 2 types of syntaxes (and their combination via logical && and || operations) are valid for Camlex. If provided expression has different signature – then CamlexNET.NonSupportedExpressionException
will be thrown.
Download Links
You can download Camlex.NET from CodeProject or from CodePlex.
Additional Resources
You can find another scenarios examples on CodePlex or on the Documentation page on CodePlex site of Camlex.NET here or on blogs of the authors:
History
- 27th January, 2010: Initial version