2011-09-30 5 views
23

이 코드 줄을 참조하십시오. 이것은 ObjectResult<long?>을 리턴하는 저장 프로시 듀어의 호출입니다. 긴 값을 추출하기 위해 나는 선택을 추가 :.NET 엔터티 프레임 워크 - IEnumerable VS. IQueryable

는 IntelliSense를 바탕으로
dbContext.FindCoursesWithKeywords(keywords).Select(l => l.Value); 

이 선택 IEnumerable<long>를 반환합니다.

어딘가에 읽었는지, 아니면 그냥이 가정에 익숙해 졌는지 확실하지 않습니다. EF API가 IEnumerable (및 IQueryable이 아님)을 반환하면 결과가 구체화되었다는 것을 항상 생각했습니다. 그들이 데이터베이스에서 뽑혔다는 의미입니다.

오늘 내가 잘못된 것이라고 알았습니다 (또는 아마도 버그입니까?). 난 당신이 동안 변경 사항을 저장하기 위해 노력하고 있음을

은 기본적으로

"세션에서 실행중인 다른 스레드 가 있기 때문에 새로운 트랜잭션이 허용되지 않습니다",이 오류를 알려주는 오류가 계속 DB 리더가 여전히 레코드를 읽는 중입니다.

은 결국 나는 (나는 장거리 슛으로 간주 것)에 의해 그것을 해결하고 IEnumerable<long> ...

그래서 구체화 ToArray() 전화를 추가 - 하단 라인 - 나는 피난처 그 결과를 포함하는 EF에서 IEnumerable 결과를 기대한다 아직 실현되지 않았습니까? 그렇다면 IEnumerable이 구체화되었는지 여부를 알 수있는 방법이 있습니까? IEnumerable<T>에서 작업

감사이 그 'duhhh'질문 중 하나 인 경우 사과 ... :)

+0

EF에 대해 특별히 문서화 된 것이 있는지는 잘 모르겠지만 일반적으로 Linq의 경우 'IEnumerable '은 'IQueryable '보다 "materialized"되지 않습니다. 둘 다 일반적으로 지연된 실행을 사용한다고 가정합니다. –

+0

@Damien_The_Unbeliever : 그러나 ObjectResult 은 함수가 호출 될 때 항상 실행됩니다 (이 경우 FindCoursesWithKeywords) –

답변

27

IQueryable은 LINQ 공급자가 SQL로 해석하고 서버에서 실행하는 응용 프로그램에 선언적 LINQ 쿼리를 작성하는 경우에 사용됩니다. 쿼리가 실행 (반복)되면 IEnumerable이되고 개체는 필요한 경우 반복되므로 즉시 구체화됩니다.

일단 저장 프로 시저를 호출하면 응용 프로그램에 내장 된 선언적 쿼리가 없기 때문에 Linq에서 엔티티를 사용하지 않습니다. 쿼리/SQL은 이미 데이터베이스 서버에 있으며 방금 호출하고 있습니다. 이 경우 IEnumerable이 반환되지만 모든 결과가 즉시 구체화되지는 않습니다. 결과가 반복됨에 따라 구체화됩니다. 이는 개체 가져 오기를 명시 적으로 요청할 때 데이터베이스 커서/또는 .NET 데이터 판독기의 원칙입니다.당신은 과정 하나 하나를 가져 오는 있습니다

foreach (var keyword in dbContext.FindCoursesWithKeywords(keywords) 
           .Select(l => l.Value)) 
{ 
    ... 
} 

:

그래서 당신이 뭔가를 호출하면 (. 당신은 키워드에 관심이 있다면 BTW 이유는 전체 과정을로드하는 방법?). 루프를 완료하거나 중단 할 때까지 레코드를 가져 오기 위해 데이터 판독기가 열립니다.

대신이를 호출하는 경우

: 당신은 즉시 모든 결과를 실현하기 위해 쿼리를 강제 루프 메모리 대신 개방 데이터베이스 리더 컬렉션 수행

foreach (var keyword in dbContext.FindCoursesWithKeywords(keywords) 
           .ToList() // or ToArray 
           .Select(l => l.Value)) 
{ 
    ... 
} 

.

IEnumerableIQueryable의 차이는 IQueryableIEnumerable이기 때문에 데이터를 가져 오는 방식이 아닙니다. 차이점은 backing 구조입니다 (이 인터페이스를 구현해야하는 것이 있습니다).

+0

안녕하세요,이 설명에 감사드립니다!그래서 이것은 저장된 프로 시저이기 때문에 쿼리가하는 모든 기능을 지원하지 않기 때문에 IQueryable을 리턴하지 않을 것입니다. (btw, 키워드가 아닌 코스를 가져 오는 중입니다. :) – justabuzz

10

모든 추가 작업은 C# 코드, 즉 LINQ - 투 - 객체에서 일어날 것을 의미합니다. 쿼리가 이미 실행되었음을 의미하지는 않습니다.

linq-to-objects로 저하되면이 시점에 남아있는 모든 데이터를 데이터베이스에서 가져 와서 .net으로 보내야합니다. 이것은 성능을 크게 떨어 뜨릴 수 있습니다 (예를 들어 linq-to-objects는 데이터베이스 인덱스를 사용하지 않습니다). 반면에 linq-to-objects는 더 유연합니다. 왜냐하면 임의의 C# 코드를 귀하의 linq 공급자는 SQL로 번역 할 수 있습니다.

IEnumerable<T>은 지연된 쿼리이거나 이미 구체화 된 데이터가 될 수 있습니다. 표준 linq 연산자는 일반적으로 지연되며 ToArray()/ToList()은 항상 구체화됩니다.

+0

고맙습니다! 그래서 제가 알아야 할 것이 있습니까? 거기에 어떤 함의가 있습니까? 건배! – justabuzz

+0

가장 명백한 문제는'IEnumerable '로 변질되면 성능이 크게 떨어질 수 있다는 것입니다. 쿼리 시작 초기에 성능이 저하되었다고 가정하면 데이터베이스의 인덱스를 사용하여 서버에서 SQL을 사용하여 필터링하는 대신 전체 테이블을 가져와야하는 경우가 있습니다. 그래서 당신이'IEnumerable '으로 저하되는 시점에서, 가능한 한 적은 수의 아이템을 남기고 싶습니다. – CodesInChaos

+0

이것이 맞는지 확실하지 않습니다. 추가 읽기 내가 여기 + 비슷한 대답을 다른 대답을 했어 - IEnumerable 당신이 그것을 반복 할 때까지 구체화하지 않을 수도 있습니다. 내가 이것이 바로 전체 쿼리 가능 객체가 아니기 때문에 스토어드 프로 시저를 실행할 때 완전한 IQueryable을 얻을 수 있기 때문입니다. 말이된다? :) – justabuzz

-5

IEnumerable : LINQ to Object 및 LINQ to XML.

된 IQueryable : LINQ는 IEnumerable을 때까지 수분을하지 않습니다

+0

IQueryable은 아직 실행되지 않은 유형입니다. 기본적으로 그것은 "쿼리"입니다. http://msdn.microsoft.com/en-us/library/system.linq.iqueryable(v=vs.100).ASPX Virutally LINQ to SQL 또는 Linq to Anything과 관련이 없습니다. 이것은 모든 종류의 데이터 공급자에 대한 액세스를 제공하는 인터페이스입니다. – Tony

0

이 구체화 SQL합니다. 저장 프로 시저를 호출하는 경우 추가 필터가 필요 없다고 생각합니다. 매개 변수를 저장 프로 시저에 보내면 원하는 데이터 하위 집합이 반환됩니다. IEnumerable은 저장 프로 시저에 묶여 있습니다. 그러나 테이블의 전체 내용을 가져 오는 경우 응용 프로그램에서 필터링을 수행하면 전략이 있어야합니다. 마찬가지로 테이블의 IEnumerable을 ToList()하지 마십시오. 모든 행이 구체화됩니다. 경우에 따라 메모리 부족 예외가 발생합니다. 게다가 이유없이 메모리를 소비하십시오. 컨텍스트에 대해 IQueryable을 사용하면 응용 프로그램이 아닌 데이터 소스에서 테이블을 필터링 할 수 있습니다. 답으로, 당신은 그것을 구체화해야합니다. IEnumerable은 인터페이스로, 형식을 구체화하여 형식을 초기화하고 내 이해에서 무언가를 산출합니다.