구체화 된 값이 널이므로 값 유형 'Int32'로 캐스트하지 못했습니다.


193

다음 코드가 있습니다. 오류가 발생했습니다.

"구체화 된 값이 널이므로 값 유형 'Int32'로 캐스트하지 못했습니다. 결과 유형의 일반 매개 변수 또는 쿼리에서 널 입력 가능 유형을 사용해야합니다."

CreditHistory 테이블에 레코드가없는 경우

var creditsSum = (from u in context.User
                  join ch in context.CreditHistory on u.ID equals ch.UserID                                        
                  where u.ID == userID
                  select ch.Amount).Sum();

null 값을 허용하도록 쿼리를 수정하려면 어떻게해야합니까?

답변:


330

linq-to-sql 쿼리는 코드로 실행되지 않고 SQL로 변환됩니다. 때때로 이것은 예기치 않은 동작을 일으키는 "누수 추상화"입니다.

이러한 경우 중 하나는 널 처리이며 다른 위치에 예기치 않은 널이있을 수 있습니다. ...DefaultIfEmpty(0).Sum(0)이 (아주 간단한) 경우에 도움이 될 수 있습니다. 여기서 요소와 sql의 SUM반환 값 이 없을 수 null있지만 c #은 0을 기대합니다.

보다 일반적인 접근 방식은 생성 된 SQL이 예기치 않은 널을 리턴 할 위험이있을 때마다 ??변환되는 사용 방법입니다 COALESCE.

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select (int?)ch.Amount).Sum() ?? 0;

첫 번째 캐스트하는 int?이 표현은 참으로 반환 할 수있는 C # 컴파일러에게 null, 비록 Sum()다시 표시를 int. 그런 다음 일반 ??연산자를 사용하여 null사례 를 처리합니다 .

이 답변을 바탕으로 LINQ to SQL 및 LINQ to Entities에 대한 세부 정보 가 포함 된 블로그 게시물 을 작성했습니다 .


3
감사합니다 Anders, DefaultIfEmpty (0) .Sum ()을 사용한 솔루션이 제대로 작동합니다. 나는 또한 두 번째 해결책을 시도했다. (int?) ... ?? 0 ..., 이전과 같은 예외가 발생합니다.
zosim

마지막으로 이것을 테스트하고 조정하여 두 번째 버전도 작동합니다.
Anders Abel

1
빈 데이터 세트에 적용될 때 Sum () 및 기타 집계 함수는 null을 반환합니다. 정의와 달리 실제로는 기본 유형의 nullable 버전을 반환합니다.
Suncat2000

2
@recursive : 예는 LINQ-to-SQL (또는 LINQ-to-Entities)이 아니라 LINQ-to-Objects입니다. 기본 데이터 공급자는 다르게 동작합니다.
Suncat2000

이것은 좋은 생각이었습니다. 반환 객체가 nullable 속성을 갖도록 업데이트했으며 매력으로 작동했습니다.
Kremena Lalova

8

널 입력 가능 Amount필드 를 허용하려면 널 병합 연산자를 사용하여 널을 0으로 변환하십시오.

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch.Amount ?? 0).Sum();

1
팁을 사용하면 컴파일러에서 다음과 같이 말합니다. Operator '??' 'int'및 'int'유형의 피연산자에는 적용 할 수 없습니다. 내가 무엇을 잊었습니까?
zosim

@ zosim : 캐스트를 int?먼저 추가하는 이유 입니다.
Anders Abel

int?를 추가했지만 동일한 예외가 있습니다. 당신이 개발 환경을 가질 때 나는 당신에게 감사합니다. 이 구문에서 무엇이 잘못되었는지 확인하십시오.
zosim

1
@ zosim : 문제를 이해하지 못합니다. Amountis 인 경우 int이미 null이 될 수 없으며 병합이 필요하지 않습니다. 당신이 말한 오류가 발생하면 Amountnullable이 아니며 단지 null 일 것 int입니다.이 경우 null을 허용하도록 디자이너에서 linq2sql dbml 열을 변경해야합니다.
재귀

1
@ 재귀 : 금액은 int, 괜찮습니다. 금액은 이미 가치가 있습니다. CreditHistory 테이블이 비어 있기 때문에 위의 오류가 발생했다고 생각합니다. User 테이블에 하나의 레코드가 있고 CreditHistory 테이블에 0 개의 레코드가 있으며 오류가 발생합니다. DefaultIfEmpty (0) .Sum ()을 사용하면 정상적으로 작동하지만 ?? 0 오류가 발생합니다. 또 다른 질문은이 경우 가장 좋은 방법은 무엇입니까? DefaultIfEmpty (0)? 고마워
zosim

4

aggregate항목이 action을 수행하지 않는 함수를 사용 중입니다. linq 쿼리가 다음과 같은 결과를 제공하는지 확인해야합니다.

var maxOrderLevel =sdv.Any()? sdv.Max(s => s.nOrderLevel):0

11
이로 인해 sdv가 두 번 실행됩니다. 당신이 IQueryables에 원하는 것이 아닙니다
Ody

4

보기에서 선택하려고 할 때이 오류 메시지가 표시되었습니다.

문제는 최근에 뷰가 새로운 널 행 (SubscriberId 열)을 얻었고 EDMX (EF 데이터베이스 먼저)에서 업데이트되지 않았기 때문입니다.

컬럼이 작동하려면 널 입력 가능 유형이어야합니다.

var dealer = Context.Dealers.Where (x => x.dealerCode == dealerCode) .FirstOrDefault ();

보기 새로 고침 전 :

public int SubscriberId { get; set; }

보기 새로 고침 후 :

public Nullable<int> SubscriberId { get; set; }

EDMX에서 뷰를 삭제하고 다시 추가했습니다.

그것이 누군가를 돕기를 바랍니다.


이것은 또한 내 문제와 내 대답했다
사이먼 니콜스

4

이 코드를 사용했으며 올바르게 응답합니다. 출력 값만 nullable입니다.

var packesCount = await botContext.Sales.Where(s => s.CustomerId == cust.CustomerId && s.Validated)
                                .SumAsync(s => (int?)s.PackesCount);
                            if(packesCount != null)
                            {
                                // your code
                            }
                            else
                            {
                                // your code
                            }

1

이 질문에 이미 답변 된 것을 확인했습니다. 그러나 두 문장으로 나누려면 다음을 고려하십시오.

var credits = from u in context.User
              join ch in context.CreditHistory 
                  on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch;

var creditSum= credits.Sum(x => (int?)x.Amount) ?? 0;

0

런타임 에이 코드로 Entity Framework 6 에서이 오류가 발생했습니다.

var fileEventsSum = db.ImportInformations.Sum(x => x.FileEvents)

LeandroSoares에서 업데이트 :

단일 실행에 이것을 사용하십시오 :

var fileEventsSum = db.ImportInformations.Sum(x => (int?)x.FileEvents) ?? 0

실물:

이것으로 바뀌었고 효과가있었습니다.

var fileEventsSum = db.ImportInformations.Any() ? db.ImportInformations.Sum(x => x.FileEvents) : 0;

1
두 번 실행하지 않겠습니까?
nawfal

이것은 좋은 대답이 아닙니다. DB에서 두 번 검색합니다.
Leandro Soares

@nawfal 이것은 사실이지만 런타임 오류보다 훨씬 낫습니다. linq-to-sql을 절대적으로 사용할 수 있지만 lambda를 사용하면 더 어렵습니다. 물론 예외를 잡을 수는 있지만 솔루션이 두 번의 실행보다 나쁘다고 생각합니다.
Ogglas

@LeandroSoares 위의 코멘트를 참조하십시오
Ogglas

1
@LeandroSoares 멋진 하나! 내 답변을 업데이트하고 제공 한 코드와 대신 사용해야하는 설명을 사용했습니다.
Ogglas

0

나는 또한 같은 문제에 직면하고 "?"를 사용하여 열을 nullable로 설정하여 해결했습니다. 운영자.

Sequnce = db.mstquestionbanks.Where(x => x.IsDeleted == false && x.OrignalFormID == OriginalFormIDint).Select(x=><b>(int?)x.Sequence</b>).Max().ToString();

때로는 null이 반환됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.