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, скорее всего, потому что содержится не поддерживается .. Я также пытался переписать его, используя любые, (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
Любые отличные идеи? Я делаю это совершенно не так?
Решение
Содержится действительно не поддерживается (возможно, должно быть, но это другое дело полностью - мы действительно добавляем поддержку различных операторов, когда его просили)
Что касается нескольких запросов против любого, я предполагаю, что вы пытаетесь сделать динамические данные, и вы хотите достичь чего-то вроде
"X OR Y OR Z"
Это сложно, и поставщик LINQ по умолчанию будет совокупным этими кратным ключам, и, поэтому ваш пример выглядит как
"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, что теги - это массив
Хорошо, [править]!
Самый простой способ получить то, что вы на самом деле хочу это сделать что-то вдоль этих линий
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)
},
(Это не будет работать, так что не попробуйте), но немного более четко о том, что вы хотите достичь.