如何Linqify这个查询

本文关键字:查询 Linqify 如何 | 更新日期: 2023-09-27 18:27:40

我当前有一个Linq查询:

   return this.Context.StockTakeFacts
                .OrderByDescending(stf => stf.StockTakeId)
                .Where(stf => stf.FactKindId == ((int)kind))
                .Take(topCount)
                .ToList<IStockTakeFact>();

目的是返回StockTakes的topCount的每个事实,但相反,我可以看到我只会得到事实的topCount数量。

我如何Linq ify这个查询来实现我的目标?

我可以用两个查询来获得topCount StockTakeId,然后做一个"中间",但我想知道Linq可能有什么技巧。

这就是我想要打败的。请注意,这实际上更多的是关于学习,而不是无法找到解决方案。我也关心性能,不是这些查询,但总的来说,我不想只是简单地做一些事情,发现它在幕后很糟糕。比如在我下面的第二个查询中,contains子句的惩罚是什么?

List<long> stids = this.Context.StockTakes
                .OrderByDescending(st => st.StockTakeId)
                .Take(topCount)
                .Select(st => st.StockTakeId)
                .ToList<long>();
            return this.Context.StockTakeFacts
                .Where(stf => (stf.FactKindId == ((int)kind)) && (stids.Contains(stf.StockTakeId)))
                .ToList<IStockTakeFact>();

如何Linqify这个查询

这个怎么样?

 return this.Context.StockTakeFacts
                .OrderByDescending(stf => stf.StockTakeId)
                .Where(stf => stf.FactKindId == ((int)kind))
                .Take(topCount)
                .Select(stf=>stf.Fact)
                .ToList();

如果我已经正确理解了你想要的东西,那么:

return this.Context.StockTakes
    .OrderByDescending(st => st.StockTakeId)
    .Take(topCount)
    .Join(
        this.Context.StockTakeFacts,
        st => st.StockTakeId,
        stf => stf.StockTakeId,
        (st, stf) => stf)
    .OrderByDescending(stf => stf.StockTakeId)
    .ToList<IStockTakeFact>();

以下是我的尝试,主要使用查询语法并使用两个独立的查询:

var stids =
     from st in this.Context.StockTakes
     orderby st.StockTakeId descending
     select st.StockTakeId;
var topFacts =
    from stid in stids.Take(topCount)
    join stf in this.Context.StockTakeFacts
    on stid equals stf.StockTakeId
    where stf.FactKindId == (int)kind
    select stf;
 return topFacts.ToList<IStockTakeFact>();

正如其他人所建议的,你想要的是加入。因为联接扩展有太多的参数,它们可能会有点令人困惑——所以我在执行联接时更喜欢查询语法——例如,如果顺序错误,编译器会出错。到目前为止,Join比过滤器更可取,这不仅是因为它阐明了数据是如何连接在一起的,而且出于性能原因,因为它在数据库中使用时使用索引,在linq中使用时对对象使用散列。

您应该注意,我在第二个查询中调用Take是为了限制在第二次查询中使用的topCount stid。我本可以在stids查询的选择行上使用into(即查询延续)来组合这两个查询,而不是使用两个查询。但这会造成将其限制为topCount项的混乱。另一种选择是把stids查询放在括号里,然后调用它的Take。相反,把它分成两个查询对我来说似乎是最干净的

每当我认为编译器可以推断类型时,我通常会避免指定泛型类型;然而,IStockTakeFact几乎可以肯定是一个接口,无论实现它的具体类型是什么,它都可能包含在this.Context.StockTakeFacts;中,这就需要在ToList调用上指定泛型类型。通常,我会在ToList调用中省略泛型类型参数——这似乎是我个人品味的一个元素,你的可能会有所不同。如果this.Context.StockTakeFacts已经是List<IStockTakeFact>,则可以安全地省略ToList调用上的泛型类型。