2009-09-14 2 views
8

IQueryable에 C# 확장 방법이 있습니다. FindNewCustomers()FindCustomersRegisteredAfter(int year) 등 내가 LINQ to SQL에 대해 쿼리를 함께 "연결"하는 데 사용합니다. LINQ-to-SQL 컴파일 된 쿼리 문제 (컴파일되지 않은 쿼리로 작동)

지금 내 문제 : 나는

private static Func<MyDataContext, SearchInfo, IQueryable<Customer>> 
     CQFindAll = 
      CompiledQuery.Compile((MyDataContext dc, SearchInfo info) => 
       dc.Contacts.Select(c => c).FindCustomersRegisteredAfter(info.RegYear) 
          .OrderBy(info.OrderInfo) 
          .Skip(info.SkipCount) 
          .Take(info.PageSize)); 

FindCustomersRegisteredAfter(int year) 방법은 확장 방법은 IQueryable을 복용 및이를 반환 : 컴파일 된 쿼리를 만들 예컨대을합니다. OrderBy 메서드는 문자열 (예 : "FirstName ASC"가 FirstName 오름차순 필드를 정렬 함)을 기반으로 동적 표현식을 만드는 확장 메서드 (System.Linq.Dynamic)입니다. SkipTake은 기본 제공 방법입니다.

이상 (컴파일 된 쿼리는 아니지만 일반 쿼리)은 으로 작동합니다. 쿼리가, 그냥 일반 LINQ 쿼리를 비 컴파일 된 경우

Method 'System.Linq.IQueryable`1[Domain.Customer] FindCustomersRegisteredAfter[Customer](System.Linq.IQueryable`1[Domain.Customer], Int32)' has no supported translation to SQL.

다시 한번, 이 완벽하게 작동 : 내가 컴파일 된 쿼리에 넣어되면, 나는 다음과 같은 오류를했다. 이 오류는 CompiledQuery.Compile() 내에있는 경우에만 나타납니다.

도움말 ??

편집 :

SELECT [t1].[Id], [t1].[FirstName], [t1].[LastName], 
     [t1].[RegYear], [t1].[DeletedOn] 
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[LastName]) AS [ROW_NUMBER], 
     [t0].[Id], [t0].[FirstName], [t0].[LastName], [t0].[RegYear], 
     [t0].[DeletedOn] 
FROM [dbo].[Contacts] AS [t0] 
WHERE ([t0].[RegYear] > @p0) AND ([t0].[DeletedOn] IS NULL) 
    ) AS [t1] 
WHERE [t1].[ROW_NUMBER] BETWEEN @p1 + 1 AND @p1 + @p2 
ORDER BY [t1].[ROW_NUMBER] 

그래서 당신이 볼 : 내가 var에 쿼리를 통해 쿼리 = (...) CompiledQuery.Compile의 내부와 같은 방법으로 작성하는 경우, 이것은 SQL이 생성된다 SQL은 완벽하게 번역이 가능하므로 반복적으로 작업하기 위해 @ p0, @ p1 및 @ p2 만 입력하면됩니다! CompiledQuery.Compile의 문제점은 무엇입니까?!?

업데이트 : @B 매개 변수가 아니기 때문에 OrderBy가 작동하지 않는다는 것을 알고 있습니다. 나는 아직도 CompiledQuery.Compile이 내 확장 메소드와 함께 작동하지 않는 이유를 알아 내려고하고있다. 이 주제에 대한 인터넷 정보는 거의 존재하지 않습니다.

+5

왜 이것이 커뮤니티 위키인지 이해할 수 없습니다. – JustLoren

답변

3

나는 컴파일 된 쿼리를 SQL로 변환 할 수 있어야한다고 생각한다. 확장 메서드는 사용할 수 없다. "일반적인"쿼리로 작성한 SQL을 프로파일 링하는 경우 모든 행을 확장 메소드에 제공 할 수 있도록 전체 테이블을 선택하는 경우가 있습니다.

필터링 논리를 쿼리 (표현식 트리의 일부로)에 넣으면 SQL로 변환하고 서버 측을 실행할 수 있습니다.

또한 Skip 때문에 OrderBy가 문제가됩니다. SQL로 변환 할 수 있도록해야합니다. 그렇지 않으면 LINQ는 클라이언트 측에서 필터링하기 위해 모든 행을 반환해야합니다.

LINQ 식으로 표현할 수 없다면 서버에서 SQL 함수를 만들고이를 DataContext에 매핑하는 것이 좋습니다. LINQ는이를 T-SQL 함수 호출로 변환 할 수 있습니다.

편집 :

은 내가 확장 방법은 식 트리를 구축하지 않은 가정 한 것 같아요. 죄송합니다.

이 문제는 유사한 것으로 보이는 link을 고려하십시오.더 자세히 설명하는 다른 link을 참조합니다.

MethodCallExpression이 문제인 것처럼 보입니다.

The code is a bit long to be posted here, but similar to tomasp.net's expander, I visit every expression in the expression tree and if the node is a MethodCallExpression which calls a method that returns an expression tree, I replace that MethodCallExpression by the expression tree returned by invoking the method.

그래서, 문제가 쿼리를 컴파일 할 때 SQL로 변환 할 식 트리가 없기 때문에, 메소드가 실행되지 않는 것입니다 나타납니다.

+0

브레이크 포인트를 만들 때 컴파일 된 쿼리가 아닌 한 SQL을 완전히 생성 할 수 있음을 알 수 있습니다 (건너 뛰기, 가져 오기, orderby 등 포함). – Alex

+0

생성 된 SQL을 표시하기 위해 게시물을 편집했습니다. – Alex