【问题标题】:Find all items where child collection doesn't contain an item查找子集合不包含项目的所有项目
【发布时间】:2012-12-05 19:51:53
【问题描述】:

给定:

public class Order
{
    public string Name {get;set;}
    public List<LineItem> LineItems {get; set;}
}

public class LineItem
{
   public string Product {get; set;}
   public int Quantity {get; set;}
}

我正在尝试弄清楚如何构造一个查询,该查询将返回所有没有具有 LineItem 且产品名为“Apple”的订单

【问题讨论】:

    标签: linq ravendb


    【解决方案1】:

    我一直在考虑这个问题。它出现了几次。问题是 Raven 目前不处理 !.Any() 或 .All() 查询。

    这个特殊的例子充分简化了问题,让我想到了一条不同的道路。我相信有一个解决方案。它需要针对静态索引的 lucene 查询:

    public class Orders_ByProduct : AbstractIndexCreationTask<Order>
    {
      public Orders_ByProduct()
      {
        Map = orders => from order in orders
                        select new
                        {
                            Product = order.LineItems.Select(x => x.Product)
                        };
      }
    }
    
    var ordersWithoutApple = session.Advanced
                                    .LuceneQuery<Order, Orders_ByProduct>()
                                    .Where("*:* AND -Product: Apple")
    

    【讨论】:

    • 另见 wizzardz 的答案,它使用相同的索引形式,但他想出了如何用简单的 linq 表达查询。
    • 当人们想要在两个集合之间执行.Except.Any &amp;&amp; !.Any 时,这也很有效,例如我想找到用户所属但不活跃的所有组,并且我拥有的 Linq 是:.Where(g =&gt; g.AllUserIdsInGroup.Any(id =&gt; userId == id) &amp;&amp; !g.ActiveUserIdsInGroup.Any(id =&gt; userId == id)),它因为 !.Any 而失败,但是这个 Lucene 查询 b> 工作:"AllUserIdsInGroup:234 AND -ActiveUserIdsInGroup:234"
    【解决方案2】:

    通过与false 的明确比较,我们能够解决 RavenDB 对!.Any 缺乏支持的问题,例如:

    orders.Where(x => x.LineItems.Any(y => y.Product == "Apple") == false)
    

    【讨论】:

      【解决方案3】:

      您可以通过为查询创建索引来做到这一点

      public class GetOrdersByProductIndex: AbstractIndexCreationTask<Order,GetOrdersByProductIndex.Result>
      {
        public class Result
        {
           public string Product {get; set;}
        }
      
        public GetOrdersByProductIndex()
        {
          Map = orders => from order in orders
                          select new
                          {
                              Product = order.LineItems.Select(x => x.Product)
                          };
        }
      }
      

      现在您可以使用此索引来获取订单。您的查询应如下所示

       using(IDocumentSession session = docStore.OpenSession())
      {
         var orders  = session.Query<GetOrdersByProductIndex.Result,GetOrdersByProductIndex>
                              .Where(x=>x.Product != "Apple")
                              .As<Order>()
                              .ToList()
      }
      

      请注意,默认情况下它只会返回128条记录(由于ravendb设置的限制),如果您的查询结果超过128条记录,您应该使用Take(recordsNeeded)函数来获取数据。

      【讨论】:

      • 好吧,我觉得很傻 - linq 转换为“(-Product:Apple AND Product:*)”,这与我写的几乎相同的 lucene。我一生都无法弄清楚如何表示否定。一个简单的 != 似乎工作得很好。谢谢!
      猜你喜欢
      • 2018-06-18
      • 2017-06-14
      • 2013-05-15
      • 2021-10-26
      • 2023-03-18
      • 2017-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多