在 Sitecore 里使用 Solr 搜索 SortOrder 关联的 Item

在 C# 使用 Solr 搜索

sitecore 的配置信息文件可直接丢进 <Instance>\App_Config 下,sitecore 会自动检测配置文件更新并加载到内存中。
通常情况下,配置信息文件是放在 <Instance>\App_Config\Include\<Project> 下,<Project> 为你项目名。



通过配置启用 SortOrder 字段并获取 SortOrder

sitecore 默认是移除了 SortOrder 字段的,不过可通过打个补丁修改配置信息,如下配置 xml 启用 SortOrder 字段。
但是这种启用 SortOrder 字段有个不好的地方,当字段值为空时,在 Solr 里是找不到此字段的,且值类型为 string 类型。

EnableSortOrder_Patch.config
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <system.web>
  </system.web>
  <sitecore>
      <contentSearch>
          <indexConfigurations>
              <defaultSolrIndexConfiguration type="Sitecore.ContentSearch.SolrProvider.SolrIndexConfiguration, Sitecore.ContentSearch.SolrProvider">
                  <documentOptions type="Sitecore.ContentSearch.SolrProvider.SolrDocumentBuilderOptions, Sitecore.ContentSearch.SolrProvider">
                      <exclude hint="list:AddExcludedField">
                          <__SortOrder>
                              <patch:delete />
                          </__SortOrder>
                      </exclude>
                  </documentOptions>
              </defaultSolrIndexConfiguration>
          </indexConfigurations>
      </contentSearch>
  </sitecore>
</configuration>
C# Code
// ./SearchResultModel.cs
using Sitecore.ContentSearch;

public class SearchResultModel
{
    [IndexField(BuiltinFields.Name)]
    public virtual string ItemName { get; set; }

    // 注意此处需要填 SortOrder 的 Item name, 而不是 Title(通常在 sitecore 里直接看到就是 Title) 或者 Display Name
    // 可通过它的 ID 找出证实一下 {BA3F86A2-4A1C-4D78-B63D-91C2779C1B5E}
    // 或通过路径:/sitecore/templates/System/Templates/Sections/Appearance/Appearance/__Sortorder
    [IndexField("__Sortorder")]
    public virtual int SortOrder { get; set; }

    [IndexField(BuiltinFields.Language)]
    public virtual string Language { get; set; }

    [IndexField(BuiltinFields.LatestVersion)]
    [ScriptIgnore]
    public virtual bool IsLatestVersion { get; set; }
}

// ----------------------------------------------

// ./Sample.cs
using Sitecore.ContentSearch;
using Sitecore.Globalization;
using Sitecore.ContentSearch.Linq.Utilities;
    
try
{
    var indexName = "sitecore_web_index";
    var language = Sitecore.Globalization.Language.Parse("en");
    using (IProviderSearchContext context = ContentSearchManager.GetIndex(indexName).CreateSearchContext())
    {
        var predicate = PredicateBuilder.True<SearchResultModel>();
        if (!Sitecore.Context.PageMode.IsNormal)
            predicate = predicate.And(z => z.IsLatestVersion);

        predicate = predicate.And(z => z.Language.Equals(language.Name, StringComparison.OrdinalIgnoreCase));

        var query = context.GetQueryable<SearchResultModel>(new ThrowOnErrorExecutionContext())
            .Filter(predicate);

        // sitecore 排序的规则为:先按 SortOrder 升序排序,再按 Item name 升序排序
        query = query
            .OrderBy(z => z.SortOrder)
            .ThenBy(z => z.ItemName);

        return query.Select(x => x.Item)?.GetResults().Hits.Select(z => z.Document);
    }
}
catch (SearchServiceUnavailableException ex)
{
    // todo: handle the exception
}


*通过使用 IComputedIndexField 接口获取 SortOrder

此方法与前面不同的地方在于,当字段值为空时,在 Solr 里仍然可以搜索到此字段,且值为 100,同时值类型为 int 类型。推荐使用这种方式。
处理异常,(不得不说,现在这官网样式又更新了,更新的还真频繁。)官网说明:https://doc.sitecore.com/xmc/en/developers/xm-cloud/find-out-if-the-solr-search-service-is-available.html

AddSortOrderField_Patch.config
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <system.web>
  </system.web>
  <sitecore>
    <contentSearch>
      <indexConfigurations>
        <defaultSolrIndexConfiguration type="Sitecore.ContentSearch.SolrProvider.SolrIndexConfiguration, Sitecore.ContentSearch.SolrProvider">
          <documentOptions>
            <fields hint="raw:AddComputedIndexField">
              <field fieldName="SortOrder" returnType="int">LinkReit.Feature.Content.ChannelCard.ComputedFields.SortOrderField, LinkReit.Feature.Content.ChannelCard</field>
            </fields>
          </documentOptions>
        </defaultSolrIndexConfiguration>
      </indexConfigurations>
    </contentSearch>
  </sitecore>
</configuration>
C# Code
// ./SortOrderField.cs
using Sitecore.Data.Items;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.ComputedFields;

public class SortOrderField : IComputedIndexField
{
    public object ComputeFieldValue(IIndexable indexable)
    {
        var item = (Item)(indexable as SitecoreIndexableItem);
        if (item == null) return null;
        
        return item.Appearance.Sortorder;
    }

    public string FieldName { get; set; }

    public string ReturnType { get; set; }
}

// ----------------------------------------------

// ./SearchResultModel.cs
using Sitecore.ContentSearch;

public class SearchResultModel
{
    [IndexField(BuiltinFields.Name)]
    public virtual string ItemName { get; set; }

    // 此处 IndexFieldAttribute 构造参数需要填写的是你配置的 SortOrder 的 fieldName
    [IndexField("SortOrder")]
    public virtual int SortOrder { get; set; }

    [IndexField(BuiltinFields.Language)]
    public virtual string Language { get; set; }

    [IndexField(BuiltinFields.LatestVersion)]
    [ScriptIgnore]
    public virtual bool IsLatestVersion { get; set; }
}

// ----------------------------------------------

// ./Sample.cs
using Sitecore.ContentSearch;
using Sitecore.Globalization;
using Sitecore.ContentSearch.Linq.Utilities;
    
try
{
    var indexName = "sitecore_web_index";
    var language = Sitecore.Globalization.Language.Parse("en");
    using (IProviderSearchContext context = ContentSearchManager.GetIndex(indexName).CreateSearchContext())
    {
        var predicate = PredicateBuilder.True<SearchResultModel>();
        if (!Sitecore.Context.PageMode.IsNormal)
            predicate = predicate.And(z => z.IsLatestVersion);

        predicate = predicate.And(z => z.Language.Equals(language.Name, StringComparison.OrdinalIgnoreCase));

        var query = context.GetQueryable<SearchResultModel>(new ThrowOnErrorExecutionContext())
            .Filter(predicate);

        // sitecore 排序的规则为:先按 SortOrder 升序排序,再按 Item name 升序排序
        query = query
            .OrderBy(z => z.SortOrder)
            .ThenBy(z => z.ItemName);

        return query.Select(x => x.Item)?.GetResults().Hits.Select(z => z.Document);
    }
}
catch (SearchServiceUnavailableException ex)
{
    // todo: handle the exception
}
posted @ 2023-03-09 15:56  灵火  阅读(123)  评论(0编辑  收藏  举报