Sitecore ContentSearch LINQ 不支持的表达式节点类型:参数



在以下代码块中尝试为 Sitecore ContentSearch LINQ 查询运行 ToList 方法时,我收到以下异常消息:

Unsupported expression node type: Parameter. This could be due to ordering of   
expression statements. For example filtering after a select expression like this : 
queryable.Select(i => new { i.Id, i.Title }).Where(i => d.Title > "A"  
public virtual List<SearchResultItem> RunQuery(SearchParam param, bool showAllVersions, bool firstLoad)
{
    Assert.ArgumentNotNull(Index, "Sitecore.SharedSource.Search");
    var resultCollection = new List<SearchResultItem>();
    try
    {
        using (var context = this.Index.CreateSearchContext())
        {
            var result = context.GetQueryable<SearchResultItem>()
                                                .Where(x => HasFullText(x, param.FullTextQuery) &&
                        HasLanguage(x, param.Language) &&
                        HasRelation(x, param.RelatedIds) &&
                        HasTemplate(x, param.TemplateIds) &&
                        HasLocation(x, param.LocationIds)
                                                );
            resultCollection = result.ToList();
        }
    }
    catch (Exception exception)
    {
        Log.Error(exception.StackTrace, this);
        throw;
    }
    return resultCollection;
}

我无法弄清楚导致此问题的原因,并且似乎无法在标准控制台应用程序(末尾的源代码)中使用标准 .NET LINQ 查询重现该问题。

以下是 HasLanguage、HasRelation、HasTemplate 和 HasLocation 函数的源代码。我希望它与这些有关,因为当我删除它们并用它们的实现替换它们时(如果可能),我没有收到任何错误。但是,当留在查询中时,它们甚至无法访问(尝试调试):

    protected bool HasRefinements(SearchResultItem pseudoResult, SafeDictionary<string> refinements)
    {
        if (refinements.Count <= 0) return false;
        foreach (var refinement in refinements)
        {
            var fieldName = refinement.Key.ToLowerInvariant();
            var fieldValue = refinement.Value;
            if (pseudoResult.GetField(fieldName).Value.Equals(IdHelper.ProcessGUIDs(fieldValue)))
            {
                return true;
            }
        }
        return false;
    }
    protected bool HasLanguage(SearchResultItem pseudoResult, string language)
    {
        if (String.IsNullOrEmpty(language)) return false;
        return pseudoResult.GetField(BuiltinFields.Language).Equals(language.ToLowerInvariant());
    }
    protected bool HasFullText(SearchResultItem pseudoResult, string searchText)
    {
        if (String.IsNullOrEmpty(searchText)) return false;
        return pseudoResult.Content.Contains(searchText);
    }
    protected bool HasId(SearchResultItem pseudoResult, string fieldName, string filter)
    {
        if (String.IsNullOrEmpty(fieldName) || String.IsNullOrEmpty(filter)) return false;
        var values = IdHelper.ParseId(filter);
        foreach (var value in values.Where(ID.IsID))
        {
            if (pseudoResult.GetField(fieldName).Value.Equals(IdHelper.ProcessGUIDs(value)))
            {
                return true;
            }
        }
        return false;
    }
    protected bool HasTemplate(SearchResultItem pseudoResult, string templateIds)
    {
        if (String.IsNullOrEmpty(templateIds)) return false;
        templateIds = IdHelper.NormalizeGuid(templateIds);
        return pseudoResult.TemplateId.ToString().Equals(templateIds);
    }
    protected bool HasLocation(SearchResultItem pseudoResult, string locationIds)
    {
        return HasId(pseudoResult, BuiltinFields.Path, locationIds);
    }
    protected bool HasRelation(SearchResultItem pseudoResult, string ids)
    {
        return HasId(pseudoResult, BuiltinFields.Links, ids);
    }  

下面是使用常规 LINQ 查询的测试应用程序的源代码:

    static void Main(string[] args)
    {
        Program p = new Program();
        p.Process();
    }
    public void Process()
    {
        List<Boolean> flags = new List<Boolean>();
        flags.Add(true);
        flags.Add(false);
        flags.Add(false);
        flags.Add(true);
        flags.Add(false);
        bool b = true;
        try
        {
            List<Boolean> trueFlags = flags
                                        .Where<Boolean>(x => IsTrue(x, b))
                                        .ToList();
            Console.WriteLine(trueFlags.ToString());
            Console.ReadKey();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.StackTrace);
        }
    }
    public bool IsTrue(bool x, bool b)
    {
        return x ^ b;
    }  

我似乎在互联网上的此异常消息上找不到任何内容。

Sitecore LINQ 与 .NET 中对象的普通 LINQ 不同。就像 LINQ to SQL 不像普通的 LINQ。

实际发生的情况是,Sitecore 会解析表达式树,并将您的条件"转换/转换"为搜索查询。默认情况下,这是Lucene查询表达式 - 但使用SearchProvider,它也可以转换为SOLR表达式或Coveo表达式。以同样的方式,LINQ to SQL 转换为 SQL 表达式。您可以看到 LINQ 实际上是一个 IQueryable 而不是 IEnumerable。

在 IQuerable 上工作时,Sitecore 必须知道如何将其转换为搜索表达式。Sitecore 不知道如何在 LINQ 表达式中转换您的属性和方法,这就是您收到错误的原因。

您应该将表达式更改为仅包含可以翻译的内容或创建谓词。你应该看看 PredicateBuilder

相关内容

最新更新