使用 Sitecore 8 内容搜索的复杂查询 API
Complex Query using Sitecore 8 content search API
我正在尝试编写一个 Linq 以使用 sitecore 内容搜索遍历 ID 列表 API 但它抛出此异常
Invalid Method Call Argument Type: Field - FieldNode - Field: supplier_categories_sm - DCP.Common.Models.Shared.CategoryItem[]. Only constant arguments is supported.
//The search item class
public class EventSupplierItem : BaseSearchItem
{
[IndexField("supplier_categories_sm")]
public CategoryItem[] SupplierCategories { get; set; } //maped to multilist
}
//I have wrote custom converter to map the multilist to that item
public class CategoryItem
{
[SitecoreId]
[IndexField("_group")]
[TypeConverter(typeof(IndexFieldIDValueConverter))]
public virtual ID Id { set; get; }
[IndexField("name")]
public string Name { get; set; }
}
创建过滤谓词以获取结果的代码:
var EventCategoryID = new ID(EventSupplierFilters.SupplierCategory);
FilterOR = FilterOR.Or(x => x.SupplierCategories.Select(a => a.Id).Contains(EventCategoryID));
filter = filter.And(FilterOR.Predicate);
results = queryable.Filter(filter.Predicate);
executedResults = results.ToList();
我也尝试过使用 .Any
而不是 .Select
但仍然抛出相同的异常,因为 Sitecore 内容搜索 linq 不支持 Any
或 Select
表达方式。
有谁知道处理这个问题的最佳方法是什么?
我认为问题的根本原因是这些表达式需要解析为Lucene queries which is quite restricted compared with what you'd expect to work. The way I think of it is that everything being turned into the query needs to be resolved into a formatted string query - more information on that is explained here。
最简单的做法可能是使用单个 'Where' 查询一次比较一个事物,然后在需要复杂逻辑时将其转换为列表,然后再尝试 运行 针对它的复杂 IEnumerable 查询。
或者,您可以深入研究并尝试了解常量表达式在 LINQ 中的工作原理 - 虽然我并不真正熟悉它。
我遇到了类似的问题,并沿着使用我自己的表达式树的路线走下去。
下面是对从搜索索引中检索到的 ID 列表进行 Contains
匹配的示例。
public static Expression<Func<CustomSearchResultItem, bool>> MatchOnMultipleValues(IEnumerable<string> arrayOfIds, string parameter)
{
var predicate = PredicateBuilder.True<CustomSearchResultItem>();
foreach (var id in arrayOfIds)
{
// create dynamic expression tree for filter for Enumerable properties (multivalued)
Expression constant = Expression.Constant(id);
ParameterExpression parameterExpression = Expression.Parameter(typeof(CustomSearchResultItem), "s");
Expression property = Expression.Property(parameterExpression, parameter);
// Call contains method on IEnumerable
var callExpression = Expression.Call(typeof(Enumerable), "Contains", new[] { typeof(string) }, property, constant);
predicate = predicate.Or(Expression.Lambda<Func<CustomSearchResultItem, Boolean>>(callExpression, parameterExpression));
}
return predicate;
}
query = query.Where(ExpressionMatches.MatchOnMultipleValues(arrayIds, Id));
CustomSearchResultItem
是我自己的 POCO class,用于处理搜索结果,其功能与您的 EventSupplierItem
class 相同。 matchonmultiplevalues
方法正在对字符串数组执行包含操作,但您可以调整它以使用 CategoryItem
.
数组
是的,您需要获取 ID,然后使用它们构建查询,而不是在过滤器或中执行 select 语句。在为搜索构建一些复杂的谓词表达式时,我遇到了很多麻烦:)
Sitecore LINQ 可能无法解析您的复杂查询,请尝试以下操作,它将 return 预期结果:
var normalizedID = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(EventSupplierFilters.SupplierCategory,true);
FilterOR = FilterOR.Or(x => x["supplier_categories_sm"].Contains(normalizedID));
filter = filter.And(FilterOR.Predicate);
results = queryable.Filter(filter.Predicate);
executedResults = results.ToList();
在 Fortis 源代码中有一个如何执行此操作的示例。有 2 种扩展方法,.ContainsAnd
和 .ContainsOr
获取 Id 列表以与另一个字段进行比较。
这是来源:https://github.com/Fortis-Collection/fortis/blob/master/Fortis/Search/SearchExtensions.cs
您或许可以根据需要自定义它。
在使用中我们调用:
var query = searchContext.GetQueryable<IItemWrapper>().ContainsOr(x => x.FieldName, arrayValues);
我正在尝试编写一个 Linq 以使用 sitecore 内容搜索遍历 ID 列表 API 但它抛出此异常
Invalid Method Call Argument Type: Field - FieldNode - Field: supplier_categories_sm - DCP.Common.Models.Shared.CategoryItem[]. Only constant arguments is supported.
//The search item class
public class EventSupplierItem : BaseSearchItem
{
[IndexField("supplier_categories_sm")]
public CategoryItem[] SupplierCategories { get; set; } //maped to multilist
}
//I have wrote custom converter to map the multilist to that item
public class CategoryItem
{
[SitecoreId]
[IndexField("_group")]
[TypeConverter(typeof(IndexFieldIDValueConverter))]
public virtual ID Id { set; get; }
[IndexField("name")]
public string Name { get; set; }
}
创建过滤谓词以获取结果的代码:
var EventCategoryID = new ID(EventSupplierFilters.SupplierCategory);
FilterOR = FilterOR.Or(x => x.SupplierCategories.Select(a => a.Id).Contains(EventCategoryID));
filter = filter.And(FilterOR.Predicate);
results = queryable.Filter(filter.Predicate);
executedResults = results.ToList();
我也尝试过使用 .Any
而不是 .Select
但仍然抛出相同的异常,因为 Sitecore 内容搜索 linq 不支持 Any
或 Select
表达方式。
有谁知道处理这个问题的最佳方法是什么?
我认为问题的根本原因是这些表达式需要解析为Lucene queries which is quite restricted compared with what you'd expect to work. The way I think of it is that everything being turned into the query needs to be resolved into a formatted string query - more information on that is explained here。
最简单的做法可能是使用单个 'Where' 查询一次比较一个事物,然后在需要复杂逻辑时将其转换为列表,然后再尝试 运行 针对它的复杂 IEnumerable 查询。
或者,您可以深入研究并尝试了解常量表达式在 LINQ 中的工作原理 - 虽然我并不真正熟悉它。
我遇到了类似的问题,并沿着使用我自己的表达式树的路线走下去。
下面是对从搜索索引中检索到的 ID 列表进行 Contains
匹配的示例。
public static Expression<Func<CustomSearchResultItem, bool>> MatchOnMultipleValues(IEnumerable<string> arrayOfIds, string parameter)
{
var predicate = PredicateBuilder.True<CustomSearchResultItem>();
foreach (var id in arrayOfIds)
{
// create dynamic expression tree for filter for Enumerable properties (multivalued)
Expression constant = Expression.Constant(id);
ParameterExpression parameterExpression = Expression.Parameter(typeof(CustomSearchResultItem), "s");
Expression property = Expression.Property(parameterExpression, parameter);
// Call contains method on IEnumerable
var callExpression = Expression.Call(typeof(Enumerable), "Contains", new[] { typeof(string) }, property, constant);
predicate = predicate.Or(Expression.Lambda<Func<CustomSearchResultItem, Boolean>>(callExpression, parameterExpression));
}
return predicate;
}
query = query.Where(ExpressionMatches.MatchOnMultipleValues(arrayIds, Id));
CustomSearchResultItem
是我自己的 POCO class,用于处理搜索结果,其功能与您的 EventSupplierItem
class 相同。 matchonmultiplevalues
方法正在对字符串数组执行包含操作,但您可以调整它以使用 CategoryItem
.
是的,您需要获取 ID,然后使用它们构建查询,而不是在过滤器或中执行 select 语句。在为搜索构建一些复杂的谓词表达式时,我遇到了很多麻烦:)
Sitecore LINQ 可能无法解析您的复杂查询,请尝试以下操作,它将 return 预期结果:
var normalizedID = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(EventSupplierFilters.SupplierCategory,true);
FilterOR = FilterOR.Or(x => x["supplier_categories_sm"].Contains(normalizedID));
filter = filter.And(FilterOR.Predicate);
results = queryable.Filter(filter.Predicate);
executedResults = results.ToList();
在 Fortis 源代码中有一个如何执行此操作的示例。有 2 种扩展方法,.ContainsAnd
和 .ContainsOr
获取 Id 列表以与另一个字段进行比较。
这是来源:https://github.com/Fortis-Collection/fortis/blob/master/Fortis/Search/SearchExtensions.cs
您或许可以根据需要自定义它。
在使用中我们调用:
var query = searchContext.GetQueryable<IItemWrapper>().ContainsOr(x => x.FieldName, arrayValues);