소스 컬렉션이 비어있는 동안 LINQ Sum ()이 0을 반환하도록하는 방법


183

기본적으로 다음 쿼리를 수행 할 때 일치하는 리드가 없으면 다음 쿼리에서 예외가 발생합니다. 이 경우 예외가 발생하는 대신 합계를 0으로 설정하는 것이 좋습니다. 이것이 쿼리 자체에서 가능 query.Any()할까요? 쿼리를 저장하고 확인하는 것이 아니라 의미 합니까?

double earnings = db.Leads.Where(l => l.Date.Day == date.Day
                && l.Date.Month == date.Month
                && l.Date.Year == date.Year
                && l.Property.Type == ProtectedPropertyType.Password
                && l.Property.PropertyId == PropertyId).Sum(l => l.Amount);

2
Where반환되지 않을 것이다 null는 어떤 기록을 발견하지 않은 경우, 제로 항목의 목록을 반환합니다. 예외는 무엇입니까?
Mike Perrenoud

3
예외는 무엇입니까?
Toto

3
예외가 발생했습니다. 구체화 된 값이 null이므로 값 유형 'Int32'로 캐스트하지 못했습니다. 결과 유형의 일반 매개 변수 또는 조회는 널 입력 가능 유형을 사용해야합니다.
John Mayer

1
@ Stijn, 당신이 여전히 일한 것이 없었습니다. 문제는 SQL생성 방법 입니다. Amount실제로는 아닙니다. 실제로 null제로 결과를 처리하는 방법을 둘러싼 문제입니다. 제공된 답변을 살펴보십시오.
Mike Perrenoud

39
달러 금액에 이중 을 사용해서는 안됩니다 ! 소수의 금액도 있습니다. 정확한 양을 의도했을 때 절대로 두 배를 사용하지 마십시오. 데이터베이스 열은 decimal코드 여야합니다 decimal. 누군가가 당신에게 통계 나 별 광도, 또는 확률 론적 과정의 결과 나 전자의 전하를 위해 그것들을 사용하라고 지시 할 때까지 당신이 프로그래밍 경력에 대해 알고 float있고 잊어 버린 것을 잊어 버리세요 double! 그때까지는 잘못하고 있습니다 .
ErikE

답변:


390

다음과 같이 쿼리를 변경하십시오.

db.Leads.Where(l => l.Date.Day == date.Day
            && l.Date.Month == date.Month
            && l.Date.Year == date.Year
            && l.Property.Type == ProtectedPropertyType.Password
            && l.Property.PropertyId == PropertyId)
         .Select(l => l.Amount)
         .DefaultIfEmpty(0)
         .Sum();

이런 식으로 쿼리는 Amount필드 만 선택합니다 . 컬렉션이 비어 있으면 값이 1 인 요소를 반환 한 0다음 합계가 적용됩니다.


확실히 트릭을 수행하지만 Sum데이터베이스에서 대신 서버 측에서 먼저 금액 값 목록을 선택하지 않습니까? imo 2kay의 솔루션이 더 최적이며 적어도 의미 론적으로 정확합니다.
Maksim Vi.

3
때 @MaksimVI EF는, 최초의 구체화에 따라 쿼리를 생성합니다 IQueryable<T>체인이 정지 (일반적으로 전화 할 때 ToList, AsEnumerable, 등이 경우 Sum). SumEF Queryable Provider가 알고 처리하는 방법이며 관련 SQL 문을 생성합니다.
Simon Belanger

@SimonBelanger 나는 정정되었습니다, 합계는 DB 측에서 이루어 지지만 Amounts를 먼저 선택하는 하위 쿼리에서 만들어집니다. 기본적으로 쿼리는 SELECT SUM(a.Amount) FROM (SELECT Amount FROM Leads WHERE ...) AS a단지 대신입니다 SELECT SUM(Amount) FROM Leads. 또한 하위 쿼리에는 추가 null 검사와 단일 행 테이블을 가진 이상한 외부 조인이 있습니다.
Maksim Vi.

큰 성능 차이는 아니며 아마도 최적화되었지만 다른 솔루션이 더 깨끗하게 보인다고 생각합니다.
Maksim Vi.

5
알고 있어야 DefaultIfEmpty당신이 던질 필요가 있도록 LINQ 공급자의 숫자에 의해 지원되지 않는 ToList()또는 이전에 그것이 적용 될 수 있도록하는 경우에 그것을 사용하여 비슷한 개체에 LINQ 시나리오.
Christopher King

188

다른 핵을 사용하는 것을 선호합니다.

double earnings = db.Leads.Where(l => l.Date.Day == date.Day
                                      && l.Date.Month == date.Month
                                      && l.Date.Year == date.Year
                                      && l.Property.Type == ProtectedPropertyType.Password
                                      && l.Property.PropertyId == PropertyId)
                          .Sum(l => (double?) l.Amount) ?? 0;

18
이 허용 대답보다 훨씬 짧은 SQL 코드를 생성 SQL에 Linq를 사용하는 경우
wertzui

3
이것이 정답입니다. 다른 모든 사람들은 실패합니다. 먼저 nullable로 캐스팅 한 다음 최종 결과를 null과 비교하십시오.
Mohsen Afshin

3
이것은 Linq To EF에 대해 허용되는 답변보다 훨씬 낫습니다. 나를 위해 생성 된 SQL은 DefaultIfEmpty보다 약 3.8 배 더 좋습니다.
Florian

2
이것은 훨씬 빠릅니다.
frakon

1
이 정확한 사용 nullables은 즉, 데이터가없는 및 기본 값 사이의 차이 보여 위해 설계이기 때문에 나는이 해킹 호출 할 것이다
MikeT


4

그것은 나를 위해 이겼다 :

int Total = 0;
Total = (int)Db.Logins.Where(L => L.id == item.MyId).Sum(L => (int?)L.NumberOfLogins ?? 0);

내 LOGIN 테이블의 NUMBEROFLOGINS 필드에서 일부 값은 NULL이고 다른 값은 INT 번호입니다. 한 회사의 모든 사용자 (각 ID)의 총 NUMBEROFLOGINS를 합산합니다.


1

시험:

이중 수입 = db.Leads.Where (l => l.ShouldBeIncluded) .Sum (l => (double?) l.Amount) ?? 0 ;

" SELECT SUM ([Amount]) " 쿼리 는 빈 목록에 대해 NULL을 반환합니다. 그러나 LINQ를 사용하는 경우 " Sum (l => l.Amount) "는 double을 반환하고 " ?? "연산자를 사용하여 빈 컬렉션에 0을 설정할 수 없습니다 .

이 상황을 피하려면 LINQ가 " double? "을 예상해야합니다 . " (double?) l.Amount " 를 캐스팅하면됩니다 .

SQL에 대한 쿼리에는 영향을 미치지 않지만 LINQ는 빈 컬렉션에서 작동합니다.


0
db.Leads.Where(l => l.Date.Day == date.Day
        && l.Date.Month == date.Month
        && l.Date.Year == date.Year
        && l.Property.Type == ProtectedPropertyType.Password
        && l.Property.PropertyId == PropertyId)
     .Select(l => l.Amount)
     .ToList()
     .Sum();

1
코드에 대한 답변에 정보를 추가하십시오
Jaqen H'ghar

1
아무것도 반환하지 않기 때문에 ToList ()없이 시도하면 오류가 발생했습니다. 그러나 ToList ()는 빈 목록을 만들고 ToList (). Sum ()을 수행 할 때 오류가 발생하지 않습니다.
Mona

2
ToList원하는 것이 합계라면 여기 에서 사용하고 싶지 않을 것입니다 . 전체 결과 집합 ( Amount이 경우 각 레코드에 대해서만 )을 메모리에 반환 한 다음 Sum()해당 집합 을 반환합니다 . SQL Server를 통해 계산을 수행하는 다른 솔루션을 사용하는 것이 훨씬 좋습니다.
Josh M.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.