2011-04-12 8 views
0

단위 테스트의 경우 메모리 컬렉션에서 LINQ 쿼리의 논리를 확인합니다. 그러나 아래 시나리오에서는 LINQ와 SQL의 결과와 메모리의 결과 간 차이점을 확인했습니다.DefaultIfEmpty - LINQ to SQL 대 메모리 있음

이 예에서는 Customer, Order, Item 테이블이 있습니다. 고객이 주문한 모든 품목 수를보고 싶습니다. 나는 어떤 품목도 주문하지 않은 고객을 보여주고 싶다. SQL에서는 외부 조인이됩니다. LINQ to SQL에서 나는 이것을 썼다 ...

var itemCounts = 
    from c in Customer 
    from o in Order.Where(oo=>o.CustomerId==c.CustomerId).DefaultIfEmpty() 
    from i in Item.Where(ii=>i.OrderId==o.OrderId).DefaultIfEmpty() 
    group i by new { i.ItemId, c.CustomerId } into ig 
    select new ItemCountResult { 
    CustomerId = ig.Key.CustomerId, 
    Count = ig.Count() 
    }; 

이것은 우리가 데이터베이스를 상대로 갈 때 잘 동작한다. 주문과 함께 주문 건수와 함께 고객을 확보합니다. 단위 테스트를 위해 메모리 콜렉션을 대체 할 때 우리는 객체 참조가 예외로 설정되지 않았 음을 알 수 있습니다. 나는 줄 "i.OrderId == o.OrderId"로 좁혔습니다. 특히 o는 null입니다.

"DefaultIfEmpty"가 작동하는 방식에 따라 실제로 예상되는 동작입니다. DefaultIfEmpty는 null의 열거 가능한 단일 요소를 리턴합니다.

그럼이 코드를 두 시나리오에서 모두 작동하도록 수정하려면 어떻게해야합니까?

업데이트 : 나는이 문제를 단순화하는 동안 몇 가지 중요한 정보를 잃어 버렸습니다. 문제를 다시 설명하겠습니다.

고객에게 0-n 주문이 있습니다. 주문에 1-n 품목이 있습니다. 항목에 1-n 주문이 있습니다.

해당 항목을 주문한 고객 수와 함께 항목 목록이 필요합니다. 0 고객이 항목을 주문한 경우에도 0이 계속 반환되지만 반환되기를 원합니다.

문제는 Join-into 구문을 사용하지 못하게하는 Order와 Item 사이의 다 대다 문제입니다.

var counts = 
    from i in Items 
    from oi in OrderItems.Where(z=>z.ItemId==i.ItemId).DefaultIfEmpty() 
    from o in Orders.Where(z=>z.OrderId==oi.OrderId).DefaultIfEmpty() 
    from c in Customers.Where(z=>z.CustomerId==o.CustomerId).DefaultIfEmpty() 
    group c by new { i.ItemId, c.CustomerId } into cg 
    select new CountResult { 
    CustomerId = cg.Key.CustomerId, 
    Count = cg.Count() 
    }; 

답변

1

귀하의 질의가 pooched되어 시작하는 :

나는 현재이 같은 (희망 오타없이이 시간)이있다. 이 :

from ... 
from o in Order.Where(oo=>o.CustomerId==c.CustomerId).DefaultIfEmpty() 
from i in Item.Where(ii=>i.OrderId==o.OrderId).DefaultIfEmpty() 

... 그것은 범위에 정말 전에 o를 사용하려고합니다. 나는 놀랍다. 어떤 고객이 c.CustomerId 위해이없는 경우 o null이됩니다 - 여전히 같은 문제가

그러나
from ... 
from o in Order.Where(oo => oo.CustomerId == c.CustomerId).DefaultIfEmpty() 
from i in Item.Where(ii => ii.OrderId == o.OrderId).DefaultIfEmpty() 

은 : 그것은 당신이 원하는 것 같습니다. SQL 변환은 똑같은 동작을 보일 수는 없지만 IMO로 시작하는 것은 솔직히 약간 이상합니다.

from c in Customer 
join oi in (from o in Orders 
      join i in Items on o.OrderId equals i.OrderId 
      select new { o, i }) 
on c.CustomerId equals oi.o.CustomerId into ordersForCustomer 
select new { CustomerId = c.CustomerId, Count = ordersForCustomer.Count() }; 
+0

가 나는 O를 잘못 입력 문제를 단순화 동안 : 조인 명시 적으로 사용하여 다시, 여기

from c in Customer join i in Items on c.CustomerId equals i.Order.OrderId into items select new { CustomerId = c.CustomerId, Count = items.Count() }; 

다른 대안을 것 :

올바른 관계가 설정 한 가정, 대신 시도 대. 나는 또한 우리가 가진 관계를 버렸다. Item to Order는 실제로는 many-to-many가 아닌 one-to-many 아이템입니다. 죄송합니다. 대체 조인 구문을 사용하면 문제가 해결되지만 올바른 것입니다.하지만 다 대 다 상황에서 제대로 작동하지 않습니다. 위의 내 문제를 업데이 트합니다. – joegtp