WhereAny() causes an exception

Dec 15, 2013 at 7:31 PM
Hi,

I am trying to use WhereAny to build a dynamic CAML query - I want to get all items from a list, for which in any of the columns a search string occurs. Here is my code:
var expressions = new List<Expression<Func<SPListItem, bool>>>();
foreach (string cn in columnNames)
{
    string columnName = cn;
    string searchFor = this.searchField.Text;  // searchField is a TextBox
    expressions.Add(x => x[columnName].ToString().Contains(searchFor));
}

var camlQuery = Camlex.Query().WhereAny(expressions).ToString();
When the WhereAny() is called, I get an exception:
"Expression type 'Call' is not supported ".

Here is the stack trace:
[NonSupportedExpressionTypeException: Expression type 'Call' is not supported]
   CamlexNET.Impl.Factories.AnalyzerFactory.Create(LambdaExpression expr) +1001
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +211
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.CompositeExpressionBaseAnalyzer.IsValid(LambdaExpression expr) +236
   CamlexNET.Impl.Operations.OrElse.OrElseAnalyzer.IsValid(LambdaExpression expr) +16
   CamlexNET.Impl.GenericTranslator.TranslateWhere(LambdaExpression expr) +38
   CamlexNET.Impl.Query.WhereAny(IEnumerable`1 expressions) +78
Any idea what the problem might be? Am I doing something wrong?

Thanks,
Vasil
Coordinator
Dec 17, 2013 at 5:33 PM
kekscho hi,
instead of .ToString() use type cast:
var expressions = new List<Expression<Func<SPListItem, bool>>>();
foreach (string cn in columnNames)
{
    string columnName = cn;
    string searchFor = this.searchField.Text;
    expressions.Add(x => ((string)x[columnName]).Contains(searchFor));
}

var camlQuery = Camlex.Query().WhereAny(expressions).ToString();
Mar 5 at 11:56 AM
Hi Alex,

great, thanks for your reply. It works now as expected! :)

I have another question - since I am using the CAML query in a custom listview webpart where I can configure the list view, there is normally an additional query the user specified. What I want to achive now is:
  1. I want to use the existing query (normally the users define some sorting, grouping or ordering in it).
  2. Additionally I want to use my Camlex query I built as above.
I tried something like this:
string existingQuery = this.list.Query.Query;
var camlQuery = Camlex.Query().WhereAny(existingQuery, expressions).ToString();
but it doesn't work. Just a quick example:

I have a grouping rule in the list view:
<GroupBy Collapse="TRUE" GroupLimit="30"><FieldRef Name="Register" /></GroupBy>

When I try to combine both the grouping and my Camlex query like above, I get an IncorrectCamlException with the message "Caml specified for tag 'Where' can not be translated to code".

I am doing something wrong? Is it possible at all to achive what I am trying to do?

Thanks in advance
Vasil
Coordinator
Mar 8 at 10:21 AM
Edited Mar 8 at 10:21 AM
hello,
it is probably because existingQuery in your case contains where, orderby and groupby tags. In order to add additional conditions and fields to all of these tags, you should have these tags in separate strings and use separate methods in Camlex (WhereAll/WhereAny, GroupBy, OrderBy, ViewFields) like shown in example in the following post: Camlex.Net 3.2: add expressions to existing string queries:
string existingQuery =
    "  <OrderBy>" +
    "    <FieldRef Name=\"Modified\" Ascending=\"False\" />" +
    "  </OrderBy>";
 
var query = Camlex.Query().OrderBy(existingQuery, x => new[]{x["Title"], x["State"] as Camlex.Asc}).ToString();
will give the following result:
<OrderBy>
  <FieldRef Name="Modified" Ascending="False" />
  <FieldRef Name="Title" />
  <FieldRef Name="State" Ascending="True" />
</OrderBy>