답변:
나는 다른 사람들이 왜 당신이 하나 또는 다른 것을 사용하는지 알고 있지만, 나는 당신 이 다른 것을 의미 할 때 왜 당신이 하나를 사용해서는 안되는지 설명 할 것이라고 생각했습니다 .
참고 : 내 코드에서, 나는 일반적으로 사용 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 개 레코드를 반환해야 느낄 때 당신은 논리의 오류를 방지하는 데 도움이됩니다.
customers.Where(predicate).Single()
customers.Single(predicate)
있습니까?
조건과 일치하는 레코드가 두 개 이상 있으면 Single에서 예외가 발생합니다. 첫 번째는 항상 목록에서 첫 번째 레코드를 선택합니다. 쿼리가 1 개의 레코드 만 반환하면으로 갈 수 있습니다 First()
.
InvalidOperationException
컬렉션이 비어 있으면 둘 다 예외 가 발생합니다. 또는을 사용할 수 있습니다 SingleOrDefault()
. 목록이 비어 있으면 예외가 발생하지 않습니다.
단일()
쿼리의 단일 특정 요소를 반환
사용시 : 정확히 1 개의 요소가 예상되는 경우; 0 이상 또는 1 이상
SingleOrDefault ()
쿼리의 단일 특정 요소를 반환하거나 결과를 찾지 못한 경우 기본값을 반환합니다
사용시 : 0 개 또는 1 개의 요소가 예상되는 경우. 목록에 2 개 이상의 항목이 있으면 예외가 발생합니다.
먼저()
여러 결과가 포함 된 쿼리의 첫 번째 요소를 반환합니다.
사용시 : 하나 이상의 요소가 예상되고 첫 번째 요소 만 원하는 경우 목록에 요소가 없으면 예외가 발생합니다.
FirstOrDefault ()
요소가 많은 목록의 첫 번째 요소를 반환하거나 목록이 비어있는 경우 기본값을 반환합니다.
사용시 : 여러 요소가 예상되고 첫 번째 요소 만 원하는 경우 또는 목록이 비어 있고 지정된 유형에 대한 기본값 (과 동일)을 원합니다
default(MyObjectType)
. 예를 들어 목록 유형이 목록list<int>
에서 첫 번째 숫자를 반환하고 목록이 비어 있으면 0을 반환합니다. 인 경우list<string>
목록에서 첫 번째 문자열을 반환하거나 목록이 비어 있으면 null을 반환합니다.
First
경우 1 개 이상의 요소가 예상된다 "1 개 이상", 그리고뿐만 아니라, FirstOrDefault
요소의 양.
이 두 방법 사이에는 미묘하고 의미적인 차이가 있습니다.
Single
하나의 요소 만 포함해야하는 시퀀스에서 첫 번째 (및 유일한) 요소를 검색하는 데 사용 합니다. 시퀀스에 요소 이상이 Single
있는 경우 하나의 요소 만 있어야한다고 표시했기 때문에 호출 하면 예외가 발생합니다.
First
여러 요소를 포함 할 수있는 시퀀스에서 첫 번째 요소를 검색하는 데 사용 합니다. 시퀀스에 요소 이상이 있으면 시퀀스 First
의 첫 번째 요소 만 필요하고 더 많은 요소가 있는지 신경 쓰지 않기 때문에 호출 하면 예외가 발생하지 않습니다.
시퀀스에 요소가없는 경우 두 메소드 모두 하나 이상의 요소가 존재할 것으로 예상하므로 두 메소드 호출 모두 예외가 발생합니다.
내가 기억하면 Single ()은 첫 번째 요소 다음에 다른 요소가 있는지 확인하고 (있는 경우 예외가 발생) First ()는 요소를 가져온 후 중지합니다. 시퀀스가 비어 있으면 예외가 발생합니다.
개인적으로, 나는 항상 First ()를 사용합니다.
성능과 관련하여 : 동료와 나는 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은 항상 테스트에서 약간 빠릅니다.
직원 엔티티의 레코드 :
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 = 10
null을 반환하지만 우리가 사용함에 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을 반환합니다.