Reputation: 3640
I'm having some trouble writing a query to select items where a descendant of the item has certain properties. I'm using Sitecore 7
I want to select the item with the plane icon where any of the green check items has property X with value Y.
Do I need to do something special to index the children? My query attempt was:
var master = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index");
using (var context = master.CreateSearchContext())
{
var results = context.GetQueryable<SearchResultItem>()
.Where(x => x.TemplateId == productTemplateId
&& x.GetDescendants<SearchResultItem>(context).Any(y => y["X"] == "Y"))
.GetResults();
var hits = results.Hits.ToArray();
}
This throws the following exception:
System.NotSupportedException: The method 'GetDescendants' is not supported. Declaring type: Sitecore.ContentSearch.SearchTypes.SearchResultItem
Result StackTrace:
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitItemMethod(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitMethodCall(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.Visit(Expression expression)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitAnyMethod(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitQueryableMethod(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitMethodCall(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.Visit(Expression expression)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitBinary(BinaryExpression expression)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.Visit(Expression expression)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitWhereMethod(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitQueryableMethod(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitMethodCall(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.Visit(Expression expression)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitGetResultsMethod(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitQueryableExtensionMethod(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.VisitMethodCall(MethodCallExpression methodCall)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.Visit(Expression expression)
at Sitecore.ContentSearch.Linq.Parsing.ExpressionParser.Parse(Expression expression)
at Sitecore.ContentSearch.Linq.Parsing.GenericQueryable`2.GetQuery(Expression expression)
at Sitecore.ContentSearch.Linq.Parsing.GenericQueryable`2.Execute[TResult](Expression expression)
at Sitecore.ContentSearch.Linq.QueryableExtensions.GetResults[TSource](IQueryable`1 source)
I'm not sure why.
Upvotes: 2
Views: 2791
Reputation: 1155
You could also create a custom computed field, store the values of the checked items and query on the custom field.
Detailed explanation can be found here:
http://www.sitecore.net/nl-nl/learn/blogs/technical-blogs/john-west-sitecore-blog/posts/2013/03/sitecore-7-computed-index-fields.aspx
Edit: with this approach you'd also have to trigger an index update for the parent.parent item when you save one the checked items (you could do that using events and calling IndexCustodian.UpdateItem).
Upvotes: 0
Reputation: 171
The previous answers are correct in that the Linq to ContentSearch does not contain a definition for GetDescendants().
Another option to overcome this limitation is to create your own extension of the IQueriable similar to what's described here: http://thegrumpycoder.com/post/75297631359/extending-sitecore-contentsearch-with-iqueryable. You could create FilterDescendants(fieldName, value) extension that takes in the field name and the value to filter descendants by.
So your statement would be
var results = context.GetQueryable<SearchResultItem>()
.Where(x => x.TemplateId == productTemplateId)
.FilterDescendants(fieldName, value)
.GetResults();
Nice and clean!
Upvotes: 0
Reputation: 2422
Sitecore Content Search API does not support the use of 'GetDescendants' method, however you can use the following code as workaround,
notice that im filtering on your Green check template and not on productTemplateId:
var master = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index");
using (var context = master.CreateSearchContext())
{
var Products = new List<Item>();
var results = context.GetQueryable<SearchResultItem>()
.Where(x => x.TemplateId == GreenCheckTemplateID
&& x["X"] == "Y")
.GetResults();
foreach (SearchHit<SitecoreItem> result in results.Hits)
{
var product = result.Document.GetItem().Parent.Parent;
if(!Products.Where(i=>i.ID.Equals(product.ID).Any())
{
Products.Add(product);
}
}
}
Upvotes: 0
Reputation: 8877
You can't use GetDescendants
because it has not been implemented in the ContentSearch expression parser.
In Sitecore search you need to look for descendants by item path.
So first get the items that match template productTemplateId, then get the items whose item path start with the path of the first result.
I'm sure there is a way to do this in one expression (probably with a Join), but I wouldn't know how.
Upvotes: 1