Steve McGill
Steve McGill

Reputation: 501

How do I query multiple IDs via the ContentSearchManager?

When I have an array of Sitecore IDs, for example TargetIDs from a MultilistField, how can I query the ContentSearchManager to return all the SearchResultItem objects?

I have tried the following which gives an "Only constant arguments is supported." error.

using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
    rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(x => f.TargetIDs.Contains(x.ItemId));
    rpt.DataBind();
}

I suppose I could build up the Linq query manually with multiple OR queries. Is there a way I can use Sitecore.ContentSearch.Utilities.LinqHelper to build the query for me?

Assuming I got this technique to work, is it worth using it for only, say, 10 items? I'm just starting my first Sitecore 7 project and I have it in mind that I want to use the index as much as possible.

Finally, does the Page Editor support editing fields somehow with a SearchResultItem as the source?

Update 1 I wrote this function which utilises the predicate builder as dunston suggests. I don't know yet if this is actually worth using (instead of Items).

public static List<T> GetSearchResultItemsByIDs<T>(ID[] ids, bool mustHaveUrl = true)
    where T : Sitecore.ContentSearch.SearchTypes.SearchResultItem, new()
{
    Assert.IsNotNull(ids, "ids");
    if (!ids.Any())
    {
        return new List<T>();
    }

    using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
    {
        var predicate = PredicateBuilder.True<T>();
        predicate = ids.Aggregate(predicate, (current, id) => current.Or(p => p.ItemId == id));

        var results = s.GetQueryable<T>().Where(predicate).ToDictionary(x => x.ItemId);
        var query = from id in ids
                  let item = results.ContainsKey(id) ? results[id] : null
                  where item != null && (!mustHaveUrl || item.Url != null)
                  select item;

        return query.ToList();
    }
}

It forces the results to be in the same order as supplied in the IDs array, which in my case is important. (If anybody knows a better way of doing this, would love to know).

It also, by default, ensures that the Item has a URL.

My main code then becomes:

var f = (Sitecore.Data.Fields.MultilistField) rootItem.Fields["Main navigation links"];
rpt.DataSource = ContentSearchHelper.GetSearchResultItemsByIDs<SearchResultItem>(f.TargetIDs);
rpt.DataBind();

I'm still curious how the Page Editor copes with SearchResultItem or POCOs in general (my second question), am going to continue researching that now.

Thanks for reading, Steve

Upvotes: 3

Views: 2227

Answers (1)

dunston
dunston

Reputation: 2670

You need to use the predicate builder to create multiple OR queries, or AND queries.

The code below should work.

        using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
        {
            var predicate = PredicateBuilder.True<SearchResultItem>();

            foreach (var targetId in f.Targetids)
            {
                var tempTargetId = targetId;
                predicate = predicate.Or(x => x.ItemId == tempTargetId)
            }
            rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(predicate);
            rpt.DataBind();
        }

Upvotes: 3

Related Questions