Общий Linq с конкретными предложениями where/order by

Я хочу создать общий метод, который позволит мне выполнять поиск в индексе Sitecore 7 с помощью Linq to Sitecore (.Net 4.5).

Это будет использоваться для различных поисков, таких как:

  • Получить 5 лучших страниц последних новостей
  • Получить последние 20 страниц событий
  • Общий поиск по сайту
  • И т.д., и т.д., и т.д.

Я могу создать очень общий метод поиска, который работает для всех типов страниц. Он предоставляет общий предикат шаблона для предложения Where, который будет применим для всех типов поиска.

Однако для вышеуказанных поисков мне также нужно добавить определенные предикаты для предложения Where и определенные выражения для Order By и т. д. Намерение состояло в том, чтобы создать подклассы для каждого типа поиска, которые реализовали бы эти особенности.

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

Все классы страниц происходят от "Base".

public virtual ReadOnlyCollection<T> Search<T>() where T : Base, new()
    {
        List<T> results = new List<T>();

        using (IProviderSearchContext context = ContentSearchManager.GetIndex("sitecore_web_index").CreateSearchContext())
        {
            Expression<Func<T, bool>> outerPredicate = PredicateBuilder.True<T>();

            // Create a predicate for the template id.
            Expression<Func<T, bool>> templatePredicate = PredicateBuilder.False<T>();
            templatePredicate = templatePredicate.Or(baseItem => (baseItem.TemplateIdFromIndex.Equals("8b1fc00c76314d32b8e1bce93dd41ccd")));

            // Create a predicate for a news page search.
            Expression<Func<NewsPageBase, bool>> datePredicate = PredicateBuilder.False<NewsPageBase>();
            datePredicate = datePredicate.And(newsPage => newsPage.ArticleDate < DateTime.Now);

            // 1. outerPredicate = outerPredicate.And(datePredicate);

            // 2. IQueryable<T> searchQuery = context.GetQueryable<T>().Where(outerPredicate).OrderByDescending(newsPage => newsPage.ArticleDate).Take(5);
            IQueryable<T> searchQuery = context.GetQueryable<T>().Where(outerPredicate);

            results = searchQuery.ToList();
        }

        return new ReadOnlyCollection<T>(results);
    }

Этот код соответствует требованиям и работает.

Однако, если я раскомментирую строку, помеченную как [1], компилятор выдаст мне ошибку из-за объединения предиката общего шаблона с предикатом конкретной страницы новостей.

Ошибка: «Аргументы типа для метода Sitecore.ContentSearch.Linq.Utilities.PredicateBuilder.And(System.Linq.Expressions.Expression>, System.Linq.Expressions.Expression>)» не могут быть выведены из использования».

Это аналогичная ошибка, если я раскомментирую строку, помеченную как [2].

Как создать общий метод, который имеет определенные функции для каждого типа поиска?


person Howard    schedule 20.11.2013    source источник


Ответы (2)


Изменение вашего кода следующим образом достигает того, что вам нужно.

public virtual ReadOnlyCollection<T> Search<T>() where T : Base, new()
    {
        List<T> results = new List<T>();

        using (IProviderSearchContext context = ContentSearchManager.GetIndex("sitecore_web_index").CreateSearchContext())
        {
            Expression<Func<T, bool>> outerPredicate = PredicateBuilder.True<T>();

            // Create a predicate for a news page search.
            Expression<Func<NewsPageBase, bool>> datePredicate = PredicateBuilder.True<NewsPageBase>();
            datePredicate = datePredicate.And(newsPage => newsPage.ArticleDate < DateTime.Now);

            //outerPredicate = outerPredicate.And((Expression<Func<T,bool>>)(object)datePredicate);
            outerPredicate = outerPredicate.And((Expression<Func<T, bool>>)(object)datePredicate);

            // 2. IQueryable<T> searchQuery = context.GetQueryable<T>().Where(outerPredicate).OrderByDescending(newsPage => newsPage.ArticleDate).Take(5);
            IQueryable<T> searchQuery = context.GetQueryable<T>().Where(outerPredicate);

            results = searchQuery.ToList();
        }

        return new ReadOnlyCollection<T>(results);
    }

Изменения, которые я сделал, были:

  1. Удален неиспользуемый templatePredicate - я не уверен, собирались ли вы использовать это или забыли удалить его при сокращении исходного кода.
  2. Создайте datePredicate, используя PredicateBuilder.True вместо PredicateBuilder.False — это необходимо для использования в .And(), иначе результаты не будут возвращены.
  3. Я (не)упаковываю datePredicate для использования в externalPredicate.And(). Компилятор жалуется, если вы пытаетесь привести datePredicate к Expression<Func<T, bool>>, но сначала решаете приведение к object.
person JayEss    schedule 29.01.2015

Я нашел работу вокруг.

Вместо:

Expression<Func<NewsPageBase, bool>> datePredicate = PredicateBuilder.False<NewsPageBase>();
datePredicate = datePredicate.And(newsPage => newsPage.ArticleDate < DateTime.Now);

Вы можете использовать:

Expression<Func<T, bool>> innerPredicate = PredicateBuilder.False<T>();
innerPredicate = innerPredicate.Or(item => ((DateTime)item[(ObjectIndexerKey)"article_date"] < DateTime.Now));

Для предложения OrderBy вы можете использовать:

searchQuery = searchQuery.OrderByDescending(item => item[(ObjectIndexerKey)"article_date"]);

Это будет работать, если ваш базовый класс является подклассом класса Sitecore «SearchResultItem».

person Howard    schedule 22.11.2013