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):
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:
<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:
var tokens = new List<string> { "hello", "greeting", "hi" };
var expressions = new List<Expression<Func<SPListItem, bool>>>();
foreach (string t in tokens)
{
string token = t;
expressions.Add(x => ((string)x["Title"]).Contains(token));
}
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”
:
<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:
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:
<Where>
<Eq>
<FieldRef ID="fa564e0f-0c70-4ab9-b863-0177e6ddd247" />
<Value Type="Text">Hello world</Value>
</Eq>
</Where>
The following code produces this CAML query:
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:
<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
):
<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:
string query = Camlex.Query().Where(
x => x["Status"] == (DataTypes.LookupValue)"Completed").ToString();
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:
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