迭代IQueryable而不调用ToList()

时间:2017-11-04 17:29:30

标签: c# database linq foreach iqueryable

我有一个用于生产线的数据库。它有一个Orders表,Ordertracker表,Item表和Itemtracker表。

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

我试图上传一张桌子的图片以使事情更清晰但是唉,我还没有足够的分数:C

我需要查找Itemtracker表中最后一个状态符合条件的项目,' 3'或者' 0'。

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

我用来完成此任务的步骤如下:

  1. 获取所有具有特定身份的订单。
  2. 获取该订单中的所有项目。
  3. 获取上次状态为= 0或3的所有项目。
  4. 获取第一件物品。
  5. 我的代码如下:

        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();
    
        }
    

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

    是否有更好的方法来迭代IQueryable项目以获取具有特定状态作为其最新状态的项目而不调用ToList()并预先通过结果?

    非常感谢任何建议。

1 个答案:

答案 0 :(得分:4)

使用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();
}