LINQ Single과 First


215

LINQ :

쿼리가 단일 레코드를 반환한다는 것을 확신 할 때 Single()연산자 를 사용하는 것이 더 효율적 입니까?First()

차이가 있습니까?

답변:


312

단일 레코드를 기대하는 경우 항상 코드에 명시하는 것이 좋습니다.

나는 다른 사람들이 왜 당신이 하나 또는 다른 것을 사용하는지 알고 있지만, 나는 당신 이 다른 것을 의미 할 때 왜 당신이 하나를 사용해서는 안되는지 설명 할 것이라고 생각했습니다 .

참고 : 내 코드에서, 나는 일반적으로 사용 FirstOrDefault()하고 SingleOrDefault()있지만 다른 질문입니다.

예를 들어, Customers복합 키 ( ID, Lang)를 사용하여 다른 언어로 저장하는 테이블을 보자 .

DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();

위의이 코드는 가능한 논리 오류를 발생시킵니다 (추적하기 어려움). 여러 언어로 된 고객 레코드가 있다고 가정하면 둘 이상의 레코드를 반환하지만 항상 첫 번째 레코드 만 반환합니다. 예측할 수 없습니다.

귀하의 의도는 단일 Customer사용 을 반환하는 것이므로 Single();

다음은 예외를 던질 것입니다 (이 경우 원하는 것입니다).

DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();

그런 다음 이마에 몸을 대고 자신에게 말하십시오. 나는 언어 분야를 잊었다! 다음은 올바른 버전입니다.

DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();

First() 다음 시나리오에서 유용합니다.

DBContext db = new DBContext();
NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();

하나의 객체를 반환하고 정렬을 사용하기 때문에 가장 최근에 반환 된 레코드가됩니다.

사용 Single()당신이 명시 적으로 항상 1 개 레코드를 반환해야 느낄 때 당신은 논리의 오류를 방지하는 데 도움이됩니다.


76
Single 및 First 메소드는 모두 필터링을위한 표현식 매개 변수를 사용할 수 있으므로 Where 함수가 필요하지 않습니다. 예 : 고객 고객 = db.Customers.Single (c => c.ID == 5);
Josh Noe

6
@JoshNoe-궁금합니다. 차이점이 customers.Where(predicate).Single() customers.Single(predicate)있습니까?
drzaus 2016 년

9
@drzaus-논리적으로 아닙니다. 술어를 기준으로 반환 할 값을 모두 필터링합니다. 그러나 분해를 확인했으며 Where (predicate) .Single ()에는 간단한 경우에 세 가지 추가 지침이 있습니다. 따라서 IL 전문가는 아니지만 customers.Single (predicate)이 더 효율적이어야합니다.
Josh Noe

5
@ JoshNoe 그것은 밝혀지는 것과는 정반대입니다.
AgentFire

10
@AgentFire 명세서 를 백업하려면
M. Mimpen

72

조건과 일치하는 레코드가 두 개 이상 있으면 Single에서 예외가 발생합니다. 첫 번째는 항상 목록에서 첫 번째 레코드를 선택합니다. 쿼리가 1 개의 레코드 만 반환하면으로 갈 수 있습니다 First().

InvalidOperationException컬렉션이 비어 있으면 둘 다 예외 가 발생합니다. 또는을 사용할 수 있습니다 SingleOrDefault(). 목록이 비어 있으면 예외가 발생하지 않습니다.


29

단일()

쿼리의 단일 특정 요소를 반환

사용시 : 정확히 1 개의 요소가 예상되는 경우; 0 이상 또는 1 이상

SingleOrDefault ()

쿼리의 단일 특정 요소를 반환하거나 결과를 찾지 못한 경우 기본값을 반환합니다

사용시 : 0 개 또는 1 개의 요소가 예상되는 경우. 목록에 2 개 이상의 항목이 있으면 예외가 발생합니다.

먼저()

여러 결과가 포함 된 쿼리의 첫 번째 요소를 반환합니다.

사용시 : 하나 이상의 요소가 예상되고 첫 번째 요소 만 원하는 경우 목록에 요소가 없으면 예외가 발생합니다.

FirstOrDefault ()

요소가 많은 목록의 첫 번째 요소를 반환하거나 목록이 비어있는 경우 기본값을 반환합니다.

사용시 : 여러 요소가 예상되고 첫 번째 요소 만 원하는 경우 또는 목록이 비어 있고 지정된 유형에 대한 기본값 (과 동일)을 원합니다 default(MyObjectType). 예를 들어 목록 유형이 목록 list<int>에서 첫 번째 숫자를 반환하고 목록이 비어 있으면 0을 반환합니다. 인 경우 list<string>목록에서 첫 번째 문자열을 반환하거나 목록이 비어 있으면 null을 반환합니다.


1
좋은 설명입니다. 난 단지 당신이 사용할 수있는 변경하려는 First경우 1 개 이상의 요소가 예상된다 "1 개 이상", 그리고뿐만 아니라, FirstOrDefault요소의 양.
Andrew

18

이 두 방법 사이에는 미묘하고 의미적인 차이가 있습니다.

Single하나의 요소 만 포함해야하는 시퀀스에서 첫 번째 (및 유일한) 요소를 검색하는 데 사용 합니다. 시퀀스에 요소 이상이 Single있는 경우 하나의 요소 만 있어야한다고 표시했기 때문에 호출 하면 예외가 발생합니다.

First여러 요소를 포함 할 수있는 시퀀스에서 첫 번째 요소를 검색하는 데 사용 합니다. 시퀀스에 요소 이상이 있으면 시퀀스 First의 첫 번째 요소 만 필요하고 더 많은 요소가 있는지 신경 쓰지 않기 때문에 호출 하면 예외가 발생하지 않습니다.

시퀀스에 요소가없는 경우 두 메소드 모두 하나 이상의 요소가 존재할 것으로 예상하므로 두 메소드 호출 모두 예외가 발생합니다.


17

하나 이상의 항목이있는 경우 예외가 발생하지 않게 하려면을 사용하십시오First() .

둘 다 효율적이며 첫 번째 항목을 가져갑니다. First()두 번째 항목이 있는지 확인하지 않으므로 약간 더 효율적입니다.

유일한 차이점은 Single()열거에 항목이 하나만있을 것으로 예상하고 둘 이상인 경우 예외가 발생한다는 것입니다. 당신은 사용 .Single() 특별히 던져 예외하려는 경우 이 경우입니다.


14

내가 기억하면 Single ()은 첫 번째 요소 다음에 다른 요소가 있는지 확인하고 (있는 경우 예외가 발생) First ()는 요소를 가져온 후 중지합니다. 시퀀스가 비어 있으면 예외가 발생합니다.

개인적으로, 나는 항상 First ()를 사용합니다.


2
SQL에서 그들은 실수하지 않으면 First ()는 TOP 1을 만들고 Single ()은 TOP 2를 만듭니다.
Matthijs Wessels 2016 년

10

성능과 관련하여 : 동료와 나는 Single vs First (또는 SingleOrDefault vs FirstOrDefault)의 성능에 대해 논의하고 있었고 First (또는 FirstOrDefault)가 더 빨라지고 성능이 향상 될 것이라고 주장했습니다. 더 빨리 달려).

나는 이것을 토론하는 스택 오버플로에 대한 여러 게시물을 읽었습니다. 일부는 Single 대신 First를 사용하면 약간의 성능 향상이 있다고 말합니다. 이는 First가 단순히 첫 번째 항목을 반환하는 반면 Single은 모든 결과를 스캔하여 중복이 없는지 확인해야하기 때문입니다 (예 : 테이블의 첫 번째 행에서 항목을 찾은 경우 여전히 다른 행을 조건과 일치하는 두 번째 값이 없는지 확인하십시오. 그러면 오류가 발생합니다). 나는“싱글”보다“첫 번째”가 더 빠르면서 확고한 입장에있는 것 같아서 그것을 증명하고 토론을 쉬게했다.

데이터베이스에 테스트를 설정하고 1,000,000 행의 ID UniqueIdentifier Foreign UniqueIdentifier Info nvarchar (50) 행을 추가했습니다 (숫자 "0"- "999,9999"로 채워짐)

데이터를로드하고 ID를 기본 키 필드로 설정했습니다.

LinqPad를 사용하여 내 목표는 Single을 사용하여 'Foreign'또는 'Info'에서 값을 검색하면 First를 사용하는 것보다 훨씬 나쁘다는 것을 보여주었습니다.

내가 얻은 결과를 설명 할 수 없습니다. 거의 모든 경우에 Single 또는 SingleOrDefault를 사용하는 것이 약간 더 빠릅니다. 이것은 나에게 논리적으로 이해가되지 않지만 공유하고 싶었습니다.

예 : 다음 쿼리를 사용했습니다.

var q = TestTables.First(x=>x.Info == "314638") ;
//Vs.
Var q = TestTables.Single(x=>x.Info =="314638") ; //(this was slightly faster to my surprise)

나는 'Foreign'키 필드에 대해 비슷한 쿼리를 시도했지만 First는 더 빠르다고 생각하는 인덱스되지는 않았지만 Single은 항상 테스트에서 약간 빠릅니다.


2
데이터베이스보다 색인화 된 필드에있는 경우 고유한지 확인하기 위해 스캔을 수행 할 필요가 없습니다. 이미 알고 있습니다. 따라서 오버 헤드가 없으며 서버 측의 유일한 오버 헤드는 하나의 레코드 만 반환하는 것입니다. 성능 테스트는 스스로 결정적인 방법이 아닙니다
mirhagk

1
IComparer에서 사용하지 않는 필드를 검색하는 경우 복잡한 개체에서 이러한 결과가 동일하다고 생각하지 않습니다.
Anthony Nichols

또 다른 질문이 될 것입니다. 테스트 소스를 반드시 포함하십시오 .
Sinatr

5

그들은 다르다. 둘 다 결과 집합이 비어 있지 않다고 주장하지만 단일 결과는 하나 이상의 결과가 없다고 주장합니다. 하나 이상의 결과를 다시 얻는 것이 오류이므로 아마도 그렇게 취급해야하기 때문에 1 개의 결과 만있을 것으로 예상되는 경우 개인적으로 Single을 사용합니다.


5

차이를 얻기 위해 간단한 예를 시도 할 수 있습니다. 3 행에는 예외가 발생합니다.

        List<int> records = new List<int>{1,1,3,4,5,6};
        var record = records.First(x => x == 1);
        record = records.Single(x => x == 1);

3

내가 아는 많은 사람들이 FirstOrDefault ()를 사용하지만, SingleOrDefault ()를 더 많이 사용하는 경향이 있습니다. 그러나 이것은 LINQ-to-Objects를 다루고 있습니다.


-1

직원 엔티티의 레코드 :

Employeeid = 1:이 ID를 가진 한 명의 직원 만

Firstname = Robert:이 이름을 가진 두 명 이상의 직원

Employeeid = 10:이 ID를 가진 직원이 없습니다.

이제 무엇 Single()First()의미 하는지 자세하게 이해해야합니다 .

단일()

Single ()은 테이블에 고유하게 존재하는 단일 레코드를 반환하는 데 사용되므로 아래 쿼리는 직원이 employeed =1하나 인 직원 Employeed이 1 명이므로 직원을 반환합니다 . 두 개의 레코드 EmployeeId = 1가 있으면 오류가 발생합니다 ( 에 대한 예제를 사용하는 두 번째 쿼리에서 오류가 발생했습니다 Firstname.

Employee.Single(e => e.Employeeid == 1)

위의 결과는 1을 가진 단일 레코드를 반환합니다. employeeId

Employee.Single(e => e.Firstname == "Robert")

여러 레코드가에 대한 테이블에 있기 때문에 위의 예외가 발생합니다 FirstName='Robert'. 예외는

InvalidOperationException : 시퀀스에 둘 이상의 요소가 포함되어 있습니다

Employee.Single(e => e.Employeeid == 10)

id = 10에 대한 레코드가 없으므로 예외가 다시 발생합니다. 예외는

InvalidOperationException : 시퀀스에 요소가 없습니다.

왜냐하면 EmployeeId = 10null을 반환하지만 우리가 사용함에 Single()따라 오류가 발생합니다. null 오류를 처리하려면을 사용해야합니다 SingleOrDefault().

먼저()

First ()는 여러 레코드에서 해당 레코드를 오름차순으로 정렬하여 birthdate가장 오래된 '로버트'를 반환합니다.

Employee.OrderBy(e => e. Birthdate)
.First(e => e.Firstname == "Robert")

위는 DOB에 따라 가장 오래된 Robert를 반환해야합니다.

Employee.OrderBy(e => e. Birthdate)
.First(e => e.Employeeid == 10)

id = 10에 대한 레코드가 없으므로 위의 예외가 발생합니다. null 예외를 피하려면을 FirstOrDefault()대신 사용해야합니다 First().

참고 : null 값을 반환 할 수없는 경우 에만 First()/ 만 사용할 수 있습니다 Single().

두 함수 모두 SingleOrDefault () 또는 FirstOrDefault () 를 사용하여 null 예외를 처리하고 레코드를 찾지 못하면 null을 반환합니다.


답을 설명하십시오.
MrMaavin

1
@MrMaavin 내가 업데이트했습니다. 친절하게 알려주세요.
보안관
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.