2017-11-04 15 views
2

DB를 생산 라인에 사용하고 있습니다. Orders 테이블과 Ordertracker 테이블, Item 테이블 및 Itemtracker 테이블이 있습니다.ToList()를 호출하지 않고 IQueryable을 반복합니다.

주문 및 항목 모두 상태와 다 대 다 관계가 있습니다. 트래커 테이블은 항목이 트래커에 여러 항목을 가질 수있는 방식으로 이러한 관계를 해결합니다. 각 항목은 특정 상태를가집니다. , C

나는 그의 마지막 상태 Itemtracker 테이블에서 조건에 맞는 항목을 찾을 필요가 :

나는 명확하게 일을 할 수있는 테이블의 사진을 업로드하려고하지만 아직 아아, 나는 포인트가 부족합니다 '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(); 
    
        } 
    

    을 자,이 모든 잘 작동하고 내가 필요하지만 난이 가장 좋은 방법하지 않을 수도 있음을 알고 있어요 무엇을 반환 다음과 같이

내 코드입니다. 이제는 IQueryable 컬렉션에 6 개 이상의 항목이 포함되지 않습니다.하지만 커지면 IQueryable에서 ToList()를 호출하고 메모리 내에서 결과를 반복하는 것은 좋은 생각이 아닙니다.

IQueryable 항목을 반복하여 더 나은 방법으로 ToList()를 호출하지 않고 결과를 예측하지 않고 특정 상태를 최신 상태로 가져 오는 항목을 가져올 수 있습니까?

조언을 주시면 감사하겠습니다.

+0

:

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()를 사용하여 : foreachfromvarlet에와 ifwhere에 변환 정보를 게으른 로딩. 그러면 각 루프가 새 쿼리가됩니다. 'ITEMTRACKER'는 귀하의 모델에서'ITEM'과 관련이 없습니까? –

+0

Btw의 경우,'CheckStatusOfItems'의 결과를 변수에 캐쉬 한 다음 변수에 null을 체크해야합니다. 그렇지 않으면 두 번 호출하고 쿼리를 두 번 실행합니다. 즉, 첫 번째 메서드를 모두 var firstOrder = ...로 축소 할 수 있다고했습니다. var items = ...; CheckStatusOfItems (items);'를 반환합니다. null이 아니므로 결과를 반환하고 null이면 null을 반환하므로 (null) 결과를 반환하는 것과 같습니다. – pinkfloydx33

+0

예, ITEMTRACKER는 다음과 같습니다. ITEM 테이블을 ITEMSTATUS 테이블에 조인하는 테이블 ItemID 및 OrderID는 ITEM의 PK입니다. ItemID, OrderID 및 ItemStatus는 ITEMTRACKER의 FK입니다. PK는 ItemTrackerID입니다. 이 문제를 해결할 방법이 있습니까? Thanks – Chi

답변

4

LINQ 쿼리 구문을 사용하면 명령형 반복 작성 방법과 거의 동일한 방식으로 단일 쿼리를 선언적으로 작성할 수 있습니다. 당신이 경우 슈퍼 슬로우 것을 IQueryable을 통해 반복

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

'Take (1)'이 해결책입니다. 'FirstOrDefault()'는 항상 문제를 일으킨다. –

+0

Brilliant! 고맙습니다. 올바르게 이해한다면 Take (1) 솔루션을 사용하면 항목 컬렉션을 먼저 반환해야하는 ToList() 접근 방식 대신 식 트리로 쿼리를 DB에서 실행할 수 있습니다. – Chi

+0

당신은 오신 것을 환영합니다. 두 방법 모두 단일 SQL 쿼리를 생성하고 실행합니다 (SELECT TOP 1 ...). 요점은 모든 것을'IQueryable '(가능한'query' 변수와 같이) 유지하고 끝에 한 번만 실행하는 것입니다. –