【问题标题】:Linq query with multiple Contains/Any for RavenDB具有多个包含/任何用于 RavenDB 的 Linq 查询
【发布时间】:2010-11-17 18:22:27
【问题描述】:

我有一个包含“标签”列表的文档类。比如:

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 =&gt; i.Tags.Any(t=&gt;t == tag))) 重写它,但这给了我一个奇怪的例外:

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

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

【问题讨论】:

  • GetQueryable() 返回类型是什么?你在query = query.Where(i =&gt; i.Tags.Contains(tag));做什么?查询类型是什么?
  • GetQueryable() 返回一个 IQueryable。不过,我确实可以访问整个 DocumentSession,所以这只是一个示例。

标签: c# linq ravendb


【解决方案1】:

确实不支持包含(也许应该支持,但这完全是另一回事 - 我们只是在需要时才真正添加对各种运算符的支持)

至于针对 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)"

注意:“Tags”告诉 RavenDB,Tags 是一个数组

好的,[编辑]!

获得真正想要的东西的最简单方法是按照这些思路做一些事情

                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 的方式来做到这一点,因为它并不能很好地映射 - 但它是一个可行的答案:)

我想我很想至少能够做到

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

(这行不通,所以不要尝试),但它更明确地说明了您想要实现的目标。

【讨论】:

  • 关闭,但没有雪茄! ;-) 首先,我使用的版本似乎不适用于“标签,:”语法。但是,如果我创建一个带有名为 Name 的单个属性的 Tag 类(并使用“Tags,Name:”),您的解决方案就可以工作。但它并不能完全满足我的需要。我希望它只返回那些在标签列表中具有所有标签的项目(不是任何一个标签)。
  • 好的,这更难,作为关系数据库中的基于集合的操作,您将如何做到这一点?我认为此时您实际上可能必须创建一个索引来将这些标签合并到一个字段中并指定您想要的分析器,然后使用 Lucene 查询说“请使用所有这些术语”
  • 这仍然是要走的路还是有更好的方法?
  • 现在有一个更好的答案 - 使用 .In 运算符。在此处查看更多信息stackoverflow.com/questions/7899936/…
  • @apostolov:这个问题不是同一个问题。这是在 List 属性上寻找一系列值,而不是更简单的字符串属性情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多