Linq 查询中的动态列表 - solr - Sitecore
Dynamic lists in Linq Query - solr - Sitecore
总结如下:
Sitecore - SOLR索引查询
我尝试使用一组可能会有所不同的站点来检索项目。
我有一个问题:
query = query.Where(x => x.Language == this.ItemLanguage)
.Where(x => x.Templates.Contains(new Guid("94c1f3e5ac174a319cc5bbb942fe80c6")));
这将 return 所有项目都正确。
我需要的是为此查询添加一个动态列表调用。
类似于:
.Where(x => x.Site.Any(y => siteNames.Contains(y)));
我尝试添加这行代码但出现错误:
System.ArgumentException: 'Argument must be array'
(一些细节)
项目 returned (x) 的字段 "Site" 为 List<string>
siteNames 是一个 List<String>
可变站点名称
以下代码在其他地方有效:
.Where(x => x.Site.Contains("somesite"));
有没有办法管理动态列表,或者我是否需要根据 siteNames 列表中的项目数手动生成此表达式?
.Where(x => x.Site.Contains("dynamic") || x.Site.Contains("dynamic")
|| x.Site.Contains("dynamic") || x.Site.Contains("dynamic")
|| and so on);
这是完整的代码示例:
using (var context = Sitecore.ContentSearch.ContentSearchManager.GetIndex(AccelConstants.SEARCH_INDEX).CreateSearchContext())
{
IQueryable<SearchResultModel> query = context.GetQueryable<LMSSearchResultModel>();
SearchResults<SearchResultModel> results = null;
List<string> siteNames = new List<string>();
siteNames = this.SiteNames;
// Define the base search
query = query.Where(x => x.Language == this.ItemLanguage)
.Where(x => x.Templates.Contains(new Guid("94c1f3e5ac174a319cc5bbb942fe80c6")))
.Where(x => x.Site.Any(p => siteNames.Contains(p)));
// Execute the query
results = query.GetResults();
}
站点字段是 Site_SM 的一个 solr 字段,输出如下:
使用名称 "Site" 的原因是 Sites 也是一个字段。
这不是我可以控制的代码,所以我正在使用我拥有的代码。
"site_sm":["login",
"admin",
"service",
"covid19",
"scheduler",
"system",
"publisher"],
搜索结果模型只是将计算的 solr 字段转换为 c#
public class SearchResultModel : SearchResultItem
{
[IndexField("_templates")]
public List<Guid> Templates { get; set; }
[IndexField("site_sm")]
public List<string> Site { get; set; }
}
好的,这是一种让我的搜索工作的相当黑的方法。
using (var context = Sitecore.ContentSearch.ContentSearchManager.GetIndex(AccelConstants.SEARCH_INDEX).CreateSearchContext())
{
IQueryable<SearchResultModel> query = context.GetQueryable<LMSSearchResultModel>();
SearchResults<SearchResultModel> results = null;
List<string> siteNames = new List<string>();
siteNames = this.SiteNames;
// Define the base search
// remove site filtering from query
query = query.Where(x => x.Language == this.ItemLanguage)
.Where(x => x.Templates.Contains(new Guid("94c1f3e5ac174a319cc5bbb942fe80c6")));
// Execute the query
results = query.GetResults();
// Get the results
foreach (var hit in results.Hits)
{
//move site filter code to here
if (hit.Document != null && hit.Document.Site.Any(p => siteNames.Contains(p)))
{
// Add the model to the results.
}
else
{
}
}
}
通过将站点过滤器代码移到查询之后,站点 List<string>
被实例化并在调用时具有值。这似乎是我的问题。
这样我就可以按 siteNames List<string>
中的网站进行过滤并获得我的最终结果集。
我不知道这是否是使这部分代码正常工作的最佳方式,但它确实有效。
我 运行 解决了这个确切的问题,并找到了这个 Whosebug 答案来搜索错误。事实证明,您必须从字面上理解错误并将 List<string> Site
更改为 string[] Site
才能在谓词中使用 .Any()
。
public class SearchResultModel : SearchResultItem
{
[IndexField("_templates")]
public List<Guid> Templates { get; set; }
[IndexField("site_sm")]
public string[] Site { get; set; }
}
使用 Predicate Builder 创建动态 OR(我只是用它来解决这个问题)。
Sitecore 有一个实现是:
//使用Sitecore.ContentSearch.Linq.Utilities
private IQueryable<LMSSearchResultModel> LimitSearchBySite(IQueryable<LMSSearchResultModel> query, IEnumerable<string> sites)
{
if (sites != null && sites.Any())
{
// https://www.albahari.com/nutshell/predicatebuilder.aspx
var predicate = PredicateBuilder.False<StoreLocatorResult>();
foreach (string s in site)
predicate = predicate.Or(p => p.Site.Contains(s));
return query.Where(predicate);
}
return query;
}
如果您直接使用 Solr 和 C#,最好的方法是使用此站点作为参考:
https://www.albahari.com/nutshell/predicatebuilder.aspx
最后是我所做的相同开发,但您需要将 PredicateBuilder class 添加到您的项目
这就是您需要替换的内容:
using (var context = Sitecore.ContentSearch.ContentSearchManager.GetIndex(AccelConstants.SEARCH_INDEX).CreateSearchContext())
{
IQueryable<SearchResultModel> query = context.GetQueryable<LMSSearchResultModel>();
SearchResults<SearchResultModel> results = null;
List<string> siteNames = new List<string>();
siteNames = this.SiteNames;
// Define the base search
query = query.Where(x => x.Language == this.ItemLanguage)
.Where(x => x.Templates.Contains(new Guid("94c1f3e5ac174a319cc5bbb942fe80c6")));
query = LimitSearchBySite(query, siteNames);
// Execute the query
results = query.GetResults();
}
总结如下:
Sitecore - SOLR索引查询
我尝试使用一组可能会有所不同的站点来检索项目。
我有一个问题:
query = query.Where(x => x.Language == this.ItemLanguage)
.Where(x => x.Templates.Contains(new Guid("94c1f3e5ac174a319cc5bbb942fe80c6")));
这将 return 所有项目都正确。
我需要的是为此查询添加一个动态列表调用。
类似于:
.Where(x => x.Site.Any(y => siteNames.Contains(y)));
我尝试添加这行代码但出现错误:
System.ArgumentException: 'Argument must be array'
(一些细节)
项目 returned (x) 的字段 "Site" 为 List<string>
siteNames 是一个 List<String>
可变站点名称
以下代码在其他地方有效:
.Where(x => x.Site.Contains("somesite"));
有没有办法管理动态列表,或者我是否需要根据 siteNames 列表中的项目数手动生成此表达式?
.Where(x => x.Site.Contains("dynamic") || x.Site.Contains("dynamic")
|| x.Site.Contains("dynamic") || x.Site.Contains("dynamic")
|| and so on);
这是完整的代码示例:
using (var context = Sitecore.ContentSearch.ContentSearchManager.GetIndex(AccelConstants.SEARCH_INDEX).CreateSearchContext())
{
IQueryable<SearchResultModel> query = context.GetQueryable<LMSSearchResultModel>();
SearchResults<SearchResultModel> results = null;
List<string> siteNames = new List<string>();
siteNames = this.SiteNames;
// Define the base search
query = query.Where(x => x.Language == this.ItemLanguage)
.Where(x => x.Templates.Contains(new Guid("94c1f3e5ac174a319cc5bbb942fe80c6")))
.Where(x => x.Site.Any(p => siteNames.Contains(p)));
// Execute the query
results = query.GetResults();
}
站点字段是 Site_SM 的一个 solr 字段,输出如下: 使用名称 "Site" 的原因是 Sites 也是一个字段。 这不是我可以控制的代码,所以我正在使用我拥有的代码。
"site_sm":["login", "admin", "service", "covid19", "scheduler", "system", "publisher"],
搜索结果模型只是将计算的 solr 字段转换为 c#
public class SearchResultModel : SearchResultItem
{
[IndexField("_templates")]
public List<Guid> Templates { get; set; }
[IndexField("site_sm")]
public List<string> Site { get; set; }
}
好的,这是一种让我的搜索工作的相当黑的方法。
using (var context = Sitecore.ContentSearch.ContentSearchManager.GetIndex(AccelConstants.SEARCH_INDEX).CreateSearchContext())
{
IQueryable<SearchResultModel> query = context.GetQueryable<LMSSearchResultModel>();
SearchResults<SearchResultModel> results = null;
List<string> siteNames = new List<string>();
siteNames = this.SiteNames;
// Define the base search
// remove site filtering from query
query = query.Where(x => x.Language == this.ItemLanguage)
.Where(x => x.Templates.Contains(new Guid("94c1f3e5ac174a319cc5bbb942fe80c6")));
// Execute the query
results = query.GetResults();
// Get the results
foreach (var hit in results.Hits)
{
//move site filter code to here
if (hit.Document != null && hit.Document.Site.Any(p => siteNames.Contains(p)))
{
// Add the model to the results.
}
else
{
}
}
}
通过将站点过滤器代码移到查询之后,站点 List<string>
被实例化并在调用时具有值。这似乎是我的问题。
这样我就可以按 siteNames List<string>
中的网站进行过滤并获得我的最终结果集。
我不知道这是否是使这部分代码正常工作的最佳方式,但它确实有效。
我 运行 解决了这个确切的问题,并找到了这个 Whosebug 答案来搜索错误。事实证明,您必须从字面上理解错误并将 List<string> Site
更改为 string[] Site
才能在谓词中使用 .Any()
。
public class SearchResultModel : SearchResultItem
{
[IndexField("_templates")]
public List<Guid> Templates { get; set; }
[IndexField("site_sm")]
public string[] Site { get; set; }
}
使用 Predicate Builder 创建动态 OR(我只是用它来解决这个问题)。 Sitecore 有一个实现是: //使用Sitecore.ContentSearch.Linq.Utilities
private IQueryable<LMSSearchResultModel> LimitSearchBySite(IQueryable<LMSSearchResultModel> query, IEnumerable<string> sites)
{
if (sites != null && sites.Any())
{
// https://www.albahari.com/nutshell/predicatebuilder.aspx
var predicate = PredicateBuilder.False<StoreLocatorResult>();
foreach (string s in site)
predicate = predicate.Or(p => p.Site.Contains(s));
return query.Where(predicate);
}
return query;
}
如果您直接使用 Solr 和 C#,最好的方法是使用此站点作为参考: https://www.albahari.com/nutshell/predicatebuilder.aspx
最后是我所做的相同开发,但您需要将 PredicateBuilder class 添加到您的项目
这就是您需要替换的内容:
using (var context = Sitecore.ContentSearch.ContentSearchManager.GetIndex(AccelConstants.SEARCH_INDEX).CreateSearchContext())
{
IQueryable<SearchResultModel> query = context.GetQueryable<LMSSearchResultModel>();
SearchResults<SearchResultModel> results = null;
List<string> siteNames = new List<string>();
siteNames = this.SiteNames;
// Define the base search
query = query.Where(x => x.Language == this.ItemLanguage)
.Where(x => x.Templates.Contains(new Guid("94c1f3e5ac174a319cc5bbb942fe80c6")));
query = LimitSearchBySite(query, siteNames);
// Execute the query
results = query.GetResults();
}