빈 쿼리 인 경우 최대 반환 값


175

이 쿼리가 있습니다.

int maxShoeSize = Workers
    .Where(x => x.CompanyId == 8)
    .Max(x => x.ShoeSize);

무엇을 할 것이다 maxShoeSize회사의 8 전혀 근로자가없는 경우는?

업데이트 :
예외가 아닌 0을 얻기 위해 쿼리를 어떻게 변경할 수 있습니까?


Naor : LINQPad에 대해 들어 보셨습니까?
Mitch Wheat

3
왜 '무엇을 보게 maxShoeSize될까요?' 당신이 이미 그것을 시도했다면.
jwg

@jwg : 나는 당신이 답을 알고 있는지 알고 싶었습니다 :) 결국 나는 내가 요청한 것을 수행하는 더 좋은 방법을 얻었으며 이것이 내가 의미하는 바입니다.
Naor

@Naor, 이것은 추측 게임이 아닙니다. 나는 또한 원래 질문을 내려 놓을 것이다. 당신이 대답을 알고 있다면 우리에게 그것을 줘라. 그렇지 않으면 당신은 게으르게 보인다. 지금 막 나는 같은 질문을하려고하고 예외 메시지를 포함한 모든 정보를 준비합니다.
Juan Carlos Oropeza

답변:


298
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                         .Select(x => x.ShoeSize)
                         .DefaultIfEmpty(0)
                         .Max();

제로인 DefaultIfEmpty은 필요하지 않습니다.


작동 :) 그러나 내 코드에서는 DefaultIfEmpty의 0이 필요했습니다.
Carlos Tenorio Pérez

1
질문의 첫 부분에 대해서는 여기에 완전히 대답하지 않았습니다 . 공식 문서 에 따르면 시퀀스 의 일반 유형이 참조 유형이면 null이됩니다. 그렇지 않으면 이 질문Max() 에 따라 빈 시퀀스를 호출 하면 오류가 발생합니다.
Raimund Krämer

59

나는 이것이 오래된 질문이고 받아 들여진 대답이 효과가 있다는 것을 알고 있지만,이 질문은 그러한 빈 세트가 예외 또는 결과를 초래할 것인지에 대한 내 질문에 대답했습니다 default(int).

그러나 받아 들여진 대답은 효과가 있지만 이상적인 해결책이 아닙니다 .IMHO는 여기에 나와 있지 않습니다. 따라서 나는 그것을 찾고있는 사람의 이익을 위해 내 자신의 답변으로 제공하고 있습니다.

OP의 원래 코드는 다음과 같습니다.

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize);

이것이 예외를 방지하고 기본 결과를 제공하기 위해 작성하는 방법입니다.

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize as int?) ?? 0;

이것은의 반환 형식의 원인 Max이 될 수있는 기능 int?수 있으며, null그 결과를 다음이 ??대체 null와 결과를 0.


편집
주석에서 무언가를 명확히하기 위해 Entity Framework는 현재 as키워드를 지원하지 않으므로 EF로 작업 할 때 키워드를 작성하는 방법은 다음과 같습니다.

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max<[TypeOfWorkers], int?>(x => x.ShoeSize) ?? 0;

(가)부터 [TypeOfWorkers]긴 클래스 이름이 쓸 지루한 수있는, 내가 도울 수있는 확장 메서드를 추가했습니다.

public static int MaxOrDefault<T>(this IQueryable<T> source, Expression<Func<T, int?>> selector, int nullValue = 0)
{
    return source.Max(selector) ?? nullValue;
}

이 단지 핸들 int,하지만 같은이를 위해 할 수있는 long, double당신이 필요로하는, 또는 다른 값 유형입니다. 이 확장 방법을 사용하는 것은 매우 간단합니다. 선택기 함수를 전달하고 선택적으로 null에 사용할 값을 포함합니다. 기본값은 0입니다. 따라서 위와 같이 다시 작성할 수 있습니다.

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);

잘하면 그것은 사람들을 훨씬 더 도와줍니다.


3
훌륭한 솔루션! 더 인기있는 DefaultIfEmpty답변 Max은 평가를 수행하지 않을 때만 잘 작동합니다 .
McGuireV10

@ McGuireV10 예, 결과 Select와 같은 집계 함수를 사용하려고 할 때 일반적으로 중개인으로 사용 하는 것을 좋아하지 않습니다 Max. 또한 생성 된 SQL은 추가 하위 선택 쿼리를 사용하여 추가 하위 선택 쿼리를 사용하고 null을 반환하여 빈 세트를 처리 한다고 생각합니다 (아직 테스트하지 않았습니다). 공감과 피드백에 감사드립니다! ;)
CptRobby

@ McGuireV10 마찬가지로, ShoeSize실제로 관련 Uniform엔티티 에있는 경우을 사용하지 Workers.Where(x => x.CompanyId == 8).Select(x => x.Uniform).Max(x => x.ShoeSize)않고 전체 평가를 Max함수 에 유지합니다 Workers.Where(x => x.CompanyId == 8).Max(x => x.Uniform.ShoeSize). EF가 효율적으로 쿼리를 구성하는 방법을 결정할 수 있도록 최대한의 방법을 쿼리에 사용하는 것을 선호합니다. ;-)
CptRobby

1
이것을 EntityFramework에서 작동시키지 못했습니다. 누구나 빛을 비출 수 있습니까? (DefaultIfEmpty 기술 사용).
Moe Sisko 2016 년

1
확장 방법의 일반적인 버전 :public static TResult MaxOrDefault<TElement, TResult>(this IQueryable<TElement> items, Expression<Func<TElement, TResult>> selector, TResult defaultValue = default) where TResult : struct => items.Select(selector).Max(item => (TResult?)item) ?? defaultValue;
relative_random 10


17
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                     .Select(x => x.ShoeSize)
                     .DefaultIfEmpty()
                     .Max();

10

Linq to SQL 인 경우 사용하고 싶지 않습니다. Any() SQL 서버에 여러 쿼리가 발생 때문에 .

ShoeSize널 입력 가능 필드가 아닌 경우 를 사용 .Max(..) ?? 0하면 작동하지 않지만 다음은 사용됩니다.

int maxShoeSize = Workers.Where(x = >x.CompanyId == 8).Max(x => (int?)x.ShoeSize) ?? 0;

방출 된 SQL을 절대 변경하지는 않지만, 시퀀스가 ​​비어 있으면를 대신 대신를 Max()리턴하도록 변경하여 0 을 리턴 int?합니다 int.


4
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
    .Max(x=>(int?)x.ShoeSize).GetValueOrDefault();

( ShoeSize유형 이라고 가정 int)

경우 WorkersDbSet또는 ObjectSet엔티티 프레임 워크에서 초기 쿼리는를 슬로우 InvalidOperationException하지만 빈 순서에 대해 불평하지만,이 값이 NULL이로 변환 할 수 없습니다 구체화 불평하지 int.


2

Max는 System.InvalidOperationException "시퀀스에 요소가 없습니다"를 발생시킵니다.

class Program
{
    static void Main(string[] args)
    {
        List<MyClass> list = new List<MyClass>();

        list.Add(new MyClass() { Value = 2 });

        IEnumerable<MyClass> iterator = list.Where(x => x.Value == 3); // empty iterator.

        int max = iterator.Max(x => x.Value); // throws System.InvalidOperationException
    }
}

class MyClass
{
    public int Value;
}

2

NB :의 쿼리 속도DefaultIfEmpty() 가 상당히 느려질 수 있습니다 . 제 경우에는와 간단한 쿼리였습니다 .DefaultIfEmpty(DateTime.Now.Date).

나는 그것을 프로파일하기에는 너무 게으르지 만 분명히 EF는 모든 행을 얻은 다음 Max()가치 를 취하려고했습니다 .

결론 : 때때로 처리 InvalidOperationException가 더 나은 선택 일 수 있습니다.


0

삼항 .Max()을 사용하여 술어를 처리하고 그 값을 설정할 수 있습니다.

// assumes Workers != null && Workers.Count() > 0
int maxShoeSize = Workers.Max(x => (x.CompanyId == 8) ? x.ShoeSize : 0);

가능하다면 Workers컬렉션이 null / 비어있는 것을 처리해야 하지만 구현에 따라 다릅니다.


0

당신은 이것을 시도 할 수 있습니다 :

int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 0;

Max가 int를 기대하고 null을 받고 있기 때문에 이것이 실패한다고 생각합니다. 따라서 널 병합 연산자가 적용되기 전에 이미 오류가 발생했습니다.
d219

0

Max ()를 수행하기 전에 작업자가 있는지 확인할 수 있습니다.

private int FindMaxShoeSize(IList<MyClass> workers) {
   var workersInCompany = workers.Where(x => x.CompanyId == 8);
   if(!workersInCompany.Any()) { return 0; }
   return workersInCompany.Max(x => x.ShoeSize);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.