2009-03-25 3 views
6

CompiledQuery.Compile 메서드를 사용하여 IQueryable과 연결된 Expression을 컴파일하는 방법이 있습니까? 현재 IQueryable 뒤에는 매우 큰 Expression 트리가 있습니다. IQueryable은 구성 요소를 제공하는 여러 가지 방법을 사용하여 구축되었습니다. 예를 들어, 두 개의 메소드가 IQueryable을 리턴하고 세 번째로 결합 될 수 있습니다. 이런 이유로 compile() 메서드 호출 내에서 전체 식을 명시 적으로 정의 할 수는 없습니다.평범하지 않은 IQueryable에서 Linq to SQL 쿼리 컴파일

표현식을 someIQueryable.Expression으로 컴파일 메소드에 전달하고 싶지만이 표현식은 컴파일 메소드에 필요한 형식이 아닙니다. 나는 시도하고, 컴파일 방법에 직접 쿼리를 넣어이 문제가 나타나면 예를 들면 : 나는 데이터 컨텍스트 내에서 호출 양식을

var foo = CompiledQuery.Compile<DataContext, IQueryable<User>>(dc => dc.getUsers()); 
    var bar = foo(this); 

, 나는 getUsers가 저장된 매핑되지 "라고 말하는 오류가 프로 시저 또는 사용자 정의 함수 "를 참조하십시오. 다시 한번 나는 getUsers 메소드의 내용을 다른 메소드를 사용하기 때문에 컴파일 호출을하는 곳으로 복사 할 수 없다.

"getUsers"에서 컴파일 메서드로 반환 된 IQueryable의 식을 전달할 수있는 방법이 있습니까?

업데이트 나는 다음과 같은 코드를 시스템에 내 의지를 강제하려고 :

var phony = Expression.Lambda<Func<DataContext, IQueryable<User>>>(
     getUsers().Expression, Expression.Parameter(typeof(DataContext), "dc")); 

    Func<DataContext, IQueryable<User>> wishful = CompiledQuery.Compile<DataContext, IQueryable<User>>(phony); 
    var foo = wishful(this); 

푸 끝나는 것 :

{System.Data.Linq.SqlClient.SqlProvider + OneTimeEnumerable `1 [Model.Entities.User]}

결과를 확장하고 쿼리를 실행하는 대신 foo에서 결과를 볼 수있는 옵션이 없습니다. "Operation coul d는 런타임을 불안정하게합니다.

SQL 문을 한 번만 생성하고 후속 요청에서 매개 변수화 된 명령으로 사용하는 방법을 찾아야합니다. 데이터 컨텍스트에서 GetCommand 메서드를 사용하여 수동으로 수행 할 수 있습니다.하지만 명시 적으로해야합니다. 모든 매개 변수를 설정하고 객체 매핑을 직접 수행하십시오.이 특정 쿼리의 복잡성을 감안할 때 수백 줄의 코드가 있습니다.

존 러스크 가장 유용한 정보를 제공

업데이트, 그래서 나는 그에게이 일에 승리를 수여했다. 그러나 약간의 여분 조정이 필요했고 내가 길을 따라 조우 한 몇 가지 다른 문제가 있었기 때문에 나는 대답에 'Expand'를 할 것이라고 생각했습니다. 첫째, '연산은 런타임 오류를 나타낼 수 있습니다.'오류는 표현식의 컴파일로 인한 것이 아니며 실제로 표현식 트리의 일부 캐스팅 때문에 발생했습니다. 어떤 곳에서는 올바른 유형 인 경우에도 .Cast<T>() 메서드를 호출하여 공식적으로 항목을 캐스팅해야했습니다. 너무 자세하게 설명하지 않으면 기본적으로 여러 표현식을 단일 트리로 결합하고 각 분기가 공통 클래스의 하위 유형 인 다른 유형을 반환 할 때 필요합니다.

destabalizing 문제를 해결 한 후 컴파일 문제로 돌아 왔습니다. John의 확장 솔루션이 거의있었습니다. 트리에서 메소드 호출 표현식을 찾고 메소드가 대개 리턴 할 기본 표현식으로 변환하려고했습니다. 표현식에 대한 나의 참조는 메소드 호출에 의해 제공되는 것이 아니라 속성들에 의해 제공되었습니다.그래서 이러한 유형을 포함하도록 확장을 수행하는 표현 방문자 수정할 필요 :이 방법은 모든 경우에 적합하지 않을 수 있습니다

protected override Expression VisitMemberAccess(MemberExpression m) { 
    if(m.Method.DeclaringType == typeof(ExpressionExtensions)) { 
     return new ExpressionExpander().Visit((Expression)(((System.Reflection.PropertyInfo)m.Member).GetValue(null, null))); 
    } 
    return base.VisitMemberAccess(m); 
} 

를하지만 같은 처지에 자신을 찾는 사람을 도움이 될 것입니다.

Expression<Func<DataContext, IQueryable<User>> queryableExpression = GetUsers(); 
var expressionWithSomeAddedStuff = (DataContext dc) => from u in queryableExpression.Invoke(dc) where ....; 
var expressionThatCanBeCompiled = expressionWithSomeAddedStuff.Expand(); 
var foo = CompiledQuery.Compile<DataContext, IQueryable<User>>(expressionThatCanBeCompiled); 

이 조금 자세한 보이는, 당신은 할 수 있습니다 개선 아마가이 같은

+2

위의 내용을 어떻게 분류했는지에 대해 자세히 설명해 주시겠습니까? 의미는 업데이트에 넣은 코드를 볼 수 있지만 삽입 할 위치는 컴파일되지 않습니다. "m.Method.DeclaringType"은 MemberExpression의 일부가 아니며 ExpressionExtensions는 존재하지 않습니다. –

+0

나는 expression tree manipulation과 비슷한 것을 시도하고 있으며 위의 구현에 관해 몇 가지 질문을하고있다. ExpressionExpander 및 ExpressionExtensions는 어디에 정의되어 있습니까? 내가 볼 수있는 한, 그들은 LinqKit의 일부가 아닙니다. 아마 그들은 이전 버전의 일부 였을까요? – Mel

+0

실제로 코드 샘플이 불완전하다는 것은 매우 성가시다. ExpressionExtensions는 아마도 VisitMemberAccess를 재정의하는 자신의 클래스이고 m.Method.DeclaringType은 아마 m.Member.DeclaringType으로 간주됩니다. 그러나 실제 문제는 .GetValue (null, null)은 작동하지 않습니다. – Charles

답변

2

뭔가 적어도 내 테스트에서, 작동합니다.

핵심 포인트는 LinqKit의 Invoke 및 Expand 메소드를 사용한다는 것입니다. 기본적으로 구성을 통해 쿼리를 작성한 다음 완성 된 결과를 컴파일 할 수 있습니다.

+0

고마워, 나는 그것을 조사해야 할 것이다. 필자의 접근 방식이 컴파일되지만 실제로 표현식 트리를 단일 함수로 컴파일하는지 또는 메서드 호출을 반환 된 함수로 호출하여 성능을 거의 향상시키지 못하는지 확실하지 않습니다. 확장 방법이 더 좋은 경우이를 허용 답변으로 설정합니다 – LaserJesus

+0

내 쿼리에서 Expand 메서드를 실행하면 다음 오류가 발생합니다. 'System.Linq.Expressions.MemberExpression'형식의 개체를 캐스팅 할 수 없습니다. 'System.Linq.Expressions.LambdaExpression'을 입력하십시오. – LaserJesus

+0

그 의미가 100 % 확실하지 않습니다. Invoke를 사용하여 호출 된 하위식이 람다식이 아닌 MemberExpression 일 수 있습니다. (전은 ".Something"에 해당하는 반면, 후자는 "() => ..."에 해당합니다. 즉 0 개 이상의 매개 변수가있는 본문 LinqKit은 전체 소스와 함께 제공됩니다. 두려워, 당신이 그것을 통해 디버깅 .... –