Pergunta

Eu tenho uma classe de documentos que contém uma lista de "tags". Algo como:

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

Agora eu gostaria de criar uma consulta para Ravendb que me entrega todos os itens filtrados por uma lista de tags. Ao usar a estrutura da entidade, consegui fazer isso por algo assim:

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

No entanto, isso não parece funcionar com Ravendb, provavelmente porque contém não é suportado. Eu também tentei reescrevê -lo usando qualquer (Where(i => i.Tags.Any(t=>t == tag))) Mas isso me dá uma exceção estranha:

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

Alguma ótima idéia? Estou fazendo isso completamente errado?

Foi útil?

Solução

Contém de fato ainda não é suportado (talvez deva ser, mas isso é outra questão completamente - nós realmente adicionamos suporte a vários operadores quando solicitados)

Quanto a várias consultas contra qualquer, presumo que você esteja tentando fazer dados dinâmicos e deseja alcançar algo como

"X OR Y OR Z"

Isso é complicado, e o provedor LINQ por padrão agregará aqueles múltiplos onde cláusulas com e, então seu exemplo parece

"X AND Y AND Z"

O que obviamente nunca será o caso.

Sua melhor opção para este é descer para a consulta Lucene (pelo menos por enquanto) e fazer algo assim:

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

Faz sentido?

A consulta acima vai parecer algo como

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

Nota: "Tags", informa Ravendb que as tags são uma matriz

Ok, [editar]!

A maneira mais fácil de conseguir o que você realmente querer é fazer algo nesse sentido

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

Então, para consultar seus ANDs, você pode fazer algo assim:

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

Agora, coisas a serem conscientes

       Tags = doc.Tags

Será serializando toda a matriz inteira em uma bolha gigante, pois são apenas cordas que funcionarão para este exemplo.

Estou olhando para as melhores maneiras de expressar isso, é improvável que vamos criar uma maneira Linq -ish de fazer isso, pois ele realmente não mapeia muito bem - mas é uma resposta que funcionará :)

Eu acho que gostaria de poder pelo menos fazer

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

(Isso não funcionará, então não tente), mas é um pouco mais explícito sobre o que você deseja alcançar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top