用于RavenDB的多个Contains / Any的Linq查询

时间:2010-11-17 18:22:27

标签: c# linq ravendb

我有一个包含“标签”列表的文档类。类似的东西:

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

现在我想为RavenDB创建一个查询,它将所有按标签列表过滤的项目交给我。使用实体框架时,我设法通过以下方式实现此目的:

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

有什么好主意吗?我这样做完全错了吗?

1 个答案:

答案 0 :(得分:17)

包含确实尚未得到支持(也许它应该是,但这完全是另一回事 - 我们只是在其要求时才真正添加对各种运营商的支持)

对于针对Any的多个查询,我假设您正在尝试执行动态数据,并且您希望实现类似

的功能
"X OR Y OR Z"

这是一个棘手的问题,默认情况下LINQ提供程序将使用AND聚合这些多个WHERE子句,因此您的示例看起来像

"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));

然后要查询你的ands,你可以这样做:

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

现在,要注意的事情

       Tags = doc.Tags

将整个数组序列化为一个巨型blob,因为它只是适用于此示例的字符串。

我正在寻找更好的方式来表达这一点,我们不太可能想出一种LINQ-ish的方法来实现这一点,因为它并没有真正映射得非常好 - 但它是< / em>一个可行的答案:)

我想我至少能够做到

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

(这不会起作用,所以不要尝试),但是对于你想要实现的目标更加明确。