I have seen many developers using the <contains> or <eq> element of CAML to query items based on a Managed Meta Data column. Using these elements of CAML for querying, returns irrelevant items in the result.
Consider we have a pages library with 'Enterprise Keywords' column (OOB Site Column) in the library. Lets assume we have three pages with the Enterprise Keywords as shown in the screen below.
Now if we need to fetch all the items from this library, having 'hare' or 'hares' in their 'Enterprise Keywords' column, we would end up writing a CAML query as shown below
<Query> <Where> <Or> <Contains> <FieldRef Name="TaxKeyword" /> <Value Type="Text">hare</Value> </Contains> <Contains> <FieldRef Name="TaxKeyword" /> <Value Type="Text">hares</Value> </Contains> </Or> </Where> </Query>
But this query will return all the three items from the library. Ideally we should get only one item, ie., default.aspx, as only this item is having the keyword as hare. But as we are using <contains> in the caml query, the words 'harebell' and 'sharepoint' contains the word 'hare', so these 2 items are also returned.
So, to get only the relevant items from the library, we should not use the <contains> element of CAML for querying Managed Meta Data columns. We have to use the WssIds of the enterprise keywords intead of the actual word. Also there is a new CAML element introduced in SharePoint 2010 - '<In>'. This works similar to the IN clause in a SQL query. So for the above scenario the CAML query should be as shown below
<Query> <Where> <In> <FieldRef LookupId="True" Name="TaxKeyword" /> <Values> <Value Type="Integer">WSS ID OF KEYWORD</Value> <Value Type="Integer">WSS ID OF KEYWORD</Value> </Values> </In> </Where> </Query>
How to get the WSS ID of the keyword?
Get all the keywords required which are of type TaxonomyFieldValue. This class has a property called WssId (TaxonomyFieldValue.WssId) which gives the WssId of the keyword. Using this property get the WssId of each keyword and use this Id as values inside IN element of CAML.
Use the below code to prepare the CAML query for querying the Managed Meta Data field
String CAML_QUERY = @"<Where><In><FieldRef LookupId=""True"" Name=""TaxKeyword"" /><Values>{0}</Values></In></Where>"; String VALUES = @"<Value Type=""Integer"">{0}</Value>";StringBuilder strValues = new StringBuilder(); Literal litDisplay = new Literal();
SPListItem item = SPContext.Current.ListItem; TaxonomyFieldValueCollection keywords = (TaxonomyFieldValueCollection)item["TaxKeyword"];
foreach (TaxonomyFieldValue keyword in keywords) { strValues.AppendLine(String.Format(VALUES, keyword.WssId)); }
String strQuery = String.Format(CAML_QUERY, strValues.ToString());
SPQuery sPQuery = new SPQuery(); sPQuery.Query = strQuery;
SPListItemCollection items = item.ParentList.GetItems(sPQuery);
With the above implementation we will get only default.aspx in the result for the example scenario considered in this article (ie. default.aspx). The above code is for a webpart which is used in a page, to display all the articles having the same keywords as that of the current page. Modify the code as required based on the area you use it.