代码之家  ›  专栏  ›  技术社区  ›  CodingInsomnia

具有多个Contains/Any for RavenDB的Linq查询

  •  17
  • CodingInsomnia  · 技术社区  · 14 年前

    我有一个包含“标记”列表的文档类。类似于:

    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不受支持。。我也试过用任何方法重写它( 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 回复  |  直到 14 年前
        1
  •  17
  •   Steve    11 年前

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

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

    "X OR Y OR Z"
    

    这是一个棘手的问题,LINQ提供程序默认情况下会使用和聚合那些多个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,因为对于本例来说,它只是字符串。

    我正在寻找更好的表达方式,我们不太可能想出一个简洁的方式来表达,因为它并不能很好地映射-但是 一个有效的答案:)

    我想我很想至少能

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

    (这不起作用,所以不要尝试),但它更明确地说明了你想要实现什么。