Подтвердить что ты не робот

Запрос Linq с несколькими Содержит/Любой для RavenDB

У меня есть класс документа, который содержит список "тегов". Что-то вроде:

class Item {
  string Name { get; set; }
  List<string> Tags {get; set;}
}

Теперь я хотел бы создать запрос для RavenDB, который передает мне все элементы, отфильтрованные по списку тегов. При использовании Entity Framework мне удалось сделать это примерно так:

var query = GetQueryable();
foreach (var tag in tags)
{
   query = query.Where(i => i.Tags.Contains(tag));
}

Однако, похоже, это не работает с RavenDB, скорее всего, потому что Contains не поддерживается. Я также пытался переписать его с помощью Any, (Where(i => i.Tags.Any(t=>t == tag))), но это дает мне странное исключение:

Unable to cast object of type
'System.Linq.Expressions.PrimitiveParameterExpression`1[System.String]'
to type 'System.Linq.Expressions.MemberExpression

Любые отличные идеи? Я делаю это совершенно неправильно?

4b9b3361

Ответ 1

Содержит еще не поддерживается (возможно, это должно быть, но это совсем другое дело - мы действительно добавляем поддержку для разных операторов, когда его просили)

Что касается нескольких запросов против Any, я предполагаю, что вы пытаетесь выполнить динамические данные, и вы хотите достичь чего-то вроде

"X OR Y OR Z"

Это сложная задача, и поставщик LINQ по умолчанию будет агрегировать те несколько предложений WHERE с AND, поэтому ваш пример выглядит как

"X AND Y AND Z"

Это, очевидно, никогда не будет.

Ваш лучший вариант для этого состоит в том, чтобы сбрасывать запрос Lucene (по крайней мере пока) и делать что-то вроде этого:

var results = s.Advanced.LuceneQuery<Item>()
                   .Where(string.Format("Tags,:({0})", string.Join(" OR ", tags))); 

Имеют смысл?

Запрос выше будет выглядеть примерно так:

"Tags,:(X OR Y OR Z)"

Примечание. "Теги" сообщает RavenDB, что теги - это массив

Хорошо, [edit]!

Самый простой способ получить то, что вы на самом деле хотите, это сделать что-то в этом направлении

                new IndexDefinition<Item, Item>()
                {
                    Map = docs => from doc in docs
                                  select new
                                  {
                                      Tags = doc.Tags
                                  },
                    Indexes = {{ x => x.Tags, FieldIndexing.Analyzed }}
                }.ToIndexDefinition(store.Conventions));

Затем, чтобы запросить ваши и, вы можете сделать что-то вроде этого:

                var results = s.Advanced.LuceneQuery<Item, WhateverYouCalledThatIndex>()
                   .Where(string.Format("Tags:({0})", string.Join(" AND ", tags)));

Теперь, что нужно знать о

       Tags = doc.Tags

Будет сериализовать весь этот массив в один гигантский blob, поскольку это просто строки, которые будут работать для этого примера.

Я смотрю на лучшие способы выражения этого, маловероятно, что мы придумаем способ LINQ-ish сделать это, поскольку он на самом деле не очень хорошо отображен, но это ответ, который будет работа:)

Я думаю, что мне очень хотелось бы, по крайней мере, сделать

  Map = docs => from doc in docs
                                  select new
                                  {
                                      Tags = String.Join(" ", doc.Tags)
                                  },

(Это не сработает, поэтому не пытайтесь это делать), но это немного более подробно о том, чего вы хотите достичь.