我有简单类型Question
:
public class Question
{
public Question(string id)
{
Id = id;
Tags = new List<string>();
}
public string Id { get; private set; }
public IList<string> Tags { get; set; }
}
我已经定义了这些问题的样本集:
var q1 = new Question("q1") { Tags = new List<string>() {"aa", "bb"} };
var q2 = new Question("q2") { Tags = new List<string>() {"aa"} };
var q3 = new Question("q3") { Tags = new List<string>() {"aa", "bb", "cc"} };
var q4 = new Question("q4");
var questions = new List<Question>() {q1, q2, q3, q4};
现在我需要找到所有问题,其中至少包含所有标记,来自给定的子集。子集定义如下:
string[] tags = new[] {"aa", "bb"};
我用来获得所需结果的查询是:
var result = questions.Where(x => !tags.Except(x.Tags).Any()).ToList();
结果是一个包含两个问题的列表: q1 和 q3 ,在我使用linq-to-objects时正常工作。
不幸的是,当我试图查询这些现在在RavenDB中持续存在的问题时,我得到了一个例外:
var result = DocumentSession.Query<Question>()
.Where(x => !tags.Except(x.Tags).Any()).ToList();
结果:
System.InvalidOperationException: Cannot understand how to translate value(Core.Commands.GetQuestions+<>c__DisplayClass0).tags.Except(x.Tags)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.GetPath(Expression expression, String& path, Type& memberType, Boolean& isNestedPath)
at Raven.Client.Linq.DynamicQueryProviderProcessor`1.GetMember(Expression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.VisitAny(MethodCallExpression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.VisitEnumerableMethodCall(MethodCallExpression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.VisitMethodCall(MethodCallExpression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.VisitExpression(Expression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.VisitExpression(Expression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.VisitQueryableMethodCall(MethodCallExpression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.VisitMethodCall(MethodCallExpression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.VisitExpression(Expression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.GetLuceneQueryFor(Expression expression)
at Raven.Client.Linq.RavenQueryProviderProcessor`1.Execute(Expression expression)
at Raven.Client.Linq.DynamicRavenQueryProvider`1.Execute(Expression expression)
at Raven.Client.Linq.DynamicRavenQueryProvider`1.System.Linq.IQueryProvider.Execute(Expression expression)
at Raven.Client.Linq.RavenQueryInspector`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
...
如何使用RavenDB执行我想要的操作?
答案 0 :(得分:6)
亚雷克, 你想要做的是:
var q = session.Query<Question>();
foreach(var tag in tags)
{
var currentTag = tag;
q = q.Where(x=>x.Tags.Any(xTag=>xTag == currentTag));
}
这将为您提供至少包含所有这些标签的所有问题。
答案 1 :(得分:1)
看起来LINQ Provider没有实现Except作为查询模式的一部分。如果我理解你的要求,你可以使用SequenceEquals。
var result = questions.Where(q => q.Tags.SequenceEqual(tags));
使用您提供的代码,只返回一个结果{"aa","bb"}
。如果RavenDB提供程序没有为您提供足够的查询模式实现,那么只需执行它而不使用LINQ。
答案 2 :(得分:0)
RavenDB LINQ提供程序不支持此语法,因为基础索引机制(Lucene)不允许此类查询。
然而,RavenDB中有一项新功能允许您执行此操作,有关详细信息,请参阅this thread。 注意您需要获取最新版本才能使用此功能。
您应该能够将查询编写为:
var result = session.Query<Question>("IndexName")
.Where(x => x.Tags.Any(t => t == "aa"))
.Intersect()
.Where(x => x.Tags.Any(t => t == "bb")
.ToList();
索引需要看起来像这样:
from qu in docs.Questions
from tag in qu.Tags
select new { tag }
谢谢,我一直在寻找这个新功能的另一个场景,所以当我有机会时,我会创建一个显示完整样本的要点。