Sitecore: эффективный способ использования LINQ для сравнения с идентификатором

У меня есть запрос LINQ, извлекающий список, например:

var results = SearchContext.GetQueryable<Person>()
  .Where(i => i.Enabled)
  .Where(i => i.TemplateName == "Person")
  .Random(6);

Каждый объект типа «Человек» имеет поле «Местоположение», которое также является элементом отображения Glass и, следовательно, имеет идентификатор; Я хотел бы выбирать только элементы, местоположение которых имеет определенный идентификатор.

Как я могу сделать это эффективно?

РЕДАКТИРОВАТЬ: я, вероятно, должен уточнить, что я не могу выполнить это сравнение, эффективно или нет. Поскольку GUID является объектом, и я не могу выполнить ToString в запросе LINQ, я не могу выбрать только элементы, чей элемент Location имеет определенный идентификатор. Любые подсказки о том, как это может быть достигнуто?

РЕДАКТИРОВАТЬ 2: Добавление пункта

.Where(i => i.Location.Id == this.Id)

Не работает по... какой-то причине, так как я не могу отлаживать то, что "видит" LINQ. Если я конвертирую другой идентификатор, я сравниваю его со строкой следующим образом:

var theOtherID = this.Id.ToString("N");

Затем он работает с этой строкой LINQ:

.Where(i => i["Location"].Contains(theOtherID))

Я до сих пор понятия не имею, почему.


person Emanuele Ciriachi    schedule 06.05.2015    source источник


Ответы (2)


Один из подходов состоит в том, чтобы включить отдельное свойство в Person, которое игнорируется картографом Glass, но может использоваться при поиске:

[SitecoreIgnore]
[Sitecore.ContentSearch.IndexField("location")]
public Sitecore.Data.ID LocationID { get; set; }

Вы можете использовать это в своем поиске следующим образом:

Sitecore.Data.ID locationId = Sitecore.Data.ID.Parse(stringOrGuid);
var results = SearchContext.GetQueryable<Person>()
  .Where(i => i.Enabled)
  .Where(i => i.TemplateName == "Person")
  .Where(i => i.LocationID == locationId)
  .Random(6);

Я думаю, что эффективность использования нескольких предложений where по сравнению с условными предложениями является спорной. Скорее всего, они приведут к выполнению одного и того же запроса Lucene. Я бы предпочел читабельность оптимизации в этом случае, но это только я.

person Derek Hunziker    schedule 06.05.2015
comment
Я, вероятно, должен уточнить, что я не могу выполнить это сравнение, эффективно или нет. Поскольку GUID является объектом, и я не могу выполнить ToString в запросе LINQ, я не могу выбрать только элементы, чей элемент Location имеет определенный идентификатор. Любые подсказки о том, как это может быть достигнуто? - person Emanuele Ciriachi; 06.05.2015
comment
Я не понимаю, почему вам нужно вызывать ToString(). Вы должны иметь возможность сравнивать GUID или ID напрямую. Пожалуйста, смотрите мой обновленный ответ. - person Derek Hunziker; 06.05.2015
comment
Кроме того, какую версию Sitecore вы используете здесь? Вы используете ContentSearch или что-то еще? - person Derek Hunziker; 06.05.2015
comment
7.2. Проблема в том, что идентификатор находится на дочернем объекте - местоположении, связанном с моим человеком, и прямое сравнение не работает. В конце концов я нашел странное решение, в котором все, казалось бы, интуитивно понятные решения не подходили. Соответственно обновлю свой вопрос, но все равно рассмотрю ваш ответ. - person Emanuele Ciriachi; 07.05.2015

Я не могу придумать более эффективных методов, чем использование простого оператора where, например:

var results = SearchContext.GetQueryable<Person>()
    .Where(i => i.Enabled && i.TemplateName == "Person" && 
         i.Location != null && i.Location.Id == 1)
    .Random(6);

Имейте в виду, что если вы используете оператор && вместо where для каждого параметра, вы уменьшите сложность алгоритма.

Вы также можете использовать свойство обратной навигации в Location в virtual ICollection<Person>, а затем сможете сделать это:

var results = SearchContext.GetQueryable<Location>()
    .Where(i => i.Id == 1 && i.Persons.Where(p => p.Enabled && p.TemplateName == "Person").Any())
    .Random(6);

Первый вариант по-прежнему будет наиболее эффективным, потому что второй использует sub-queries. Но стоит знать, что вы можете сделать свой поиск по-другому.

person Alexandre Severino    schedule 06.05.2015
comment
Спасибо. Дело в том, что Location.Id — это Guid Sitecore, и я не могу использовать .ToString() внутри Linq. Любая идея о том, как я могу сделать это сравнение? - person Emanuele Ciriachi; 06.05.2015
comment
Не совсем там - мне все еще нужно вернуть список людей, но мне нужно проверить идентификатор поля местоположения, который есть у каждого человека. - person Emanuele Ciriachi; 06.05.2015
comment
Попробуйте решение Дерека Ханцикера для вашей проблемы Sitecore Guid. - person Alexandre Severino; 06.05.2015
comment
Это решение не будет работать, потому что синтаксический анализатор запросов не знает, как преобразовать i.Location.ID в Location. Используйте первый ответ, чтобы добиться того, что вам нужно. - person Michael Edwards; 07.05.2015