【问题标题】:Sitecore ContentSearch LINQ Unsupported expression node type: ParameterSitecore ContentSearch LINQ 不支持的表达式节点类型:参数
【发布时间】:2014-02-16 20:01:30
【问题描述】:

尝试在以下代码块中运行 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;
    }  

我似乎在 Internet 上的这条异常消息中找不到任何内容。

【问题讨论】:

    标签: linq lucene sitecore sitecore7


    【解决方案1】:

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

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

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

    您应该将表达式更改为仅包含可以翻译或创建谓词的内容。 You should look into the PredicateBuilder

    【讨论】:

    • re:谓词构建器,我还建议在 Sitecore 7 中构建动态 linq 查询的这篇文章 getfishtank.ca/blog/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多