在不调用 ToList() 的情况下迭代 IQueryable

Iterate over an IQueryable without calling ToList()

我有一个用于生产线的数据库。它有一个订单 table、订单跟踪器 table、一个项目 table 和一个项目跟踪器 table。

订单和商品都与状态存在多对多关系。跟踪器 tables 以这样的方式解决这些关系,即一个项目可以在跟踪器中有多个条目 - 每个条目都有特定的状态。

我试图上传一张 table 的照片以使事情更清楚,但唉,我还没有足够的分数 :C

我需要找到 Itemtracker table 中最后状态满足条件“3”或“0”的项目。

然后我需要获得这些项目中的第一个。

我用来完成此操作的步骤如下:

  1. 获取所有具有特定状态的订单。
  2. 获取该订单中的所有项目。
  3. 获取最后状态为 = 0 或 3 的所有项目。
  4. 获得这些物品中的第一个。

我的代码如下:

    public ITEM GetFirstItemFailedOrNotInProductionFromCurrentOrder()
    {

        var firstOrder = GetFirstOrderInProductionAndNotCompleted();

        var items = ERPContext.ITEM.Where(i => i.OrderID == firstOrder.OrderID) as IQueryable<ITEM>;

        if (CheckStatusOfItems(items) != null)
        {
            var nextItem = CheckStatusOfItems(items);

            return nextItem ;
        }
        else
        {
            return null;
        }
    }

    private ITEM CheckStatusOfItems(IQueryable<ITEM> items)
    {
        List<ITEM> listOfItemsToProduce = new List<ITEM>();

        foreach (ITEM item in items.ToList())
        {

           var lastStatusOfItem = ERPContext.ITEMTRACKER.Where(it => it.ItemID == item.ItemID)
                                                        .OrderByDescending(it => it.ItemTrackerID).FirstOrDefault();

            if (lastStatusOfItem.ItemStatus == (int)ItemStatus.Failed || lastStatusOfItem.ItemStatus == (int)ItemStatus.Confirmed)
            {
                listOfItemsToProduce.Add(item);
            }
        }
        return listOfItemsToProduce.FirstOrDefault();

    }

现在,这一切都很好,returns 我需要什么,但我知道这可能不是最好的方法。现在我的 IQueryable 项目集合永远不会包含超过 6 个项目——但如果它可以变得更大,那么在 IQueryable 上调用 ToList() 并迭代内存中的结果可能不是一个好主意。

有没有更好的方法来遍历 IQueryable 项目以取出具有特定状态的项目作为其最新状态,而无需调用 ToList() 并遍历结果?

如有任何建议,我们将不胜感激。

使用 LINQ 查询语法,您可以以几乎与编写命令式迭代相同的方式以声明方式构建单个查询。 foreach 转换为 fromvar 转换为 letif 转换为 where

private ITEM CheckStatusOfItems(IQueryable<ITEM> items)
{
    var query =
        from item in items
        let lastStatusOfItem = ERPContext.ITEMTRACKER
            .Where(it => it.ItemID == item.ItemID)
            .OrderByDescending(it => it.ItemTrackerID)
            .FirstOrDefault()
        where (lastStatusOfItem.ItemStatus == (int)ItemStatus.Failed || lastStatusOfItem.ItemStatus == (int)ItemStatus.Confirmed)
        select item;

    return query.FirstOrDefault();
}

或者使用 from 代替 letTake(1) 代替 FirstOrDefault():

private ITEM CheckStatusOfItems(IQueryable<ITEM> items)
{
    var query =
        from item in items
        from lastStatusOfItem in ERPContext.ITEMTRACKER
            .Where(it => it.ItemID == item.ItemID)
            .OrderByDescending(it => it.ItemTrackerID)
            .Take(1)
        where (lastStatusOfItem.ItemStatus == (int)ItemStatus.Failed || lastStatusOfItem.ItemStatus == (int)ItemStatus.Confirmed)
        select item;

    return query.FirstOrDefault();
}