2016-06-01 4 views
0

linq 메소드의 이름과 속성의 이름을 전달하는 함수에서 표현 트리를 사용하여 iqueryable에서 linq 메소드를 실행하려고합니다. 하지만 내 예제 메서드는 매핑 된 속성에서만 작동합니다. 예를 들어 계산 된 속성의 최대 값을 찾으려고 할 때 예외가 발생합니다.Entity Framework에서 매핑 된 속성이없는 쿼리를 실행합니다. 표현 트리

내 클래스 :

public partial class Something 
    { 
     public int a { get; set; } 
     public int b { get; set; } 
    } 

    public partial class Something 
    { 
     public int calculated { get { return a * b; } } 
    } 

샘플 방법 :

1) 계산 저장 :

public static object ExecuteLinqMethod(IQueryable<T> q, string Field, string Method) 
    { 
     var param = Expression.Parameter(typeof(T), "p"); 

     Expression prop = Expression.Property(param, Field); 

     var exp = Expression.Lambda(prop, param); 

      Type[] types = new Type[] { q.ElementType, exp.Body.Type }; 
      var mce = Expression.Call(typeof(Queryable),Method,types,q.Expression,exp); 

      return q.Provider.Execute(mce); 
    } 
+1

왜 표현식 트리를 사용하면 EF 쿼리 공급자가 지원하지 않는 작업을 수행 할 수 있다고 생각합니까? –

+0

매핑 된 속성과 매핑되지 않은 속성의 최대, 최소, 합계 등을 찾기 위해 보편적 인 방법이 필요합니다. 이 메소드의 파라미터로서 지정된 함수 명과 프로퍼티 명을 지정합니다. 그것은 표현 트리 또는 다른 방법으로 수행 할 수 있습니다. –

+0

그런 다음 "다른 방법"을 먼저 찾은 다음 필요한 경우 표현 트리 도움말을 요청하십시오. 주요 문제는 필드가 매핑되는지 아닌지를 결정하는 방법입니다. 그리고 계산 된 속성이 사용하는 것을 알 수있는 방법이 없기 때문에 실행하는 유일한 방법은'IEnumerable '에 대해 실행하는 것입니다. –

답변

0

계산 속성을 조회 할 수 있도록, 당신은 적어도 2 가지 옵션이 있습니다 행 (또는 다른 테이블)이있는 db의 값을 가져 와서 쿼리에 사용하면 물론 데이터 모델 변경 및 데이터 중복성이 필요하지만 가장 효과적인 방법입니다. 그러나 흥미롭지 않으므로

2) SQL을 이해하는 방식으로 속성을 "계산"하는 방법을 표현할 수 있어야합니다. 즉 속성을 linq로 바꾸어야 함을 의미합니다. 표현식을 최종 쿼리에 추가합니다. 2009 년에 에릭 리 퍼트 (Eric Lippert)가 인라인에 등록한 놀라운 기사를 발견했지만 더 이상 찾을 수 없습니다. 같은 여기에 link 또 다른, 그 같은 생각을 가지고있다. 기본적으로 계산을 표현식 트리로 정의하고 코드에서 컴파일 된 버전을 사용합니다.

public partial class Something 
{ 
    [CalculatedBy("calculatedExpression")] 
    public int calculated { get { return calculatedExpression.Compile()(this); } } 
    public static Expression<Func<Something, int>> calculatedExpression = s => s.a * s.b; 
} 

(물론 당신은 캐시 할 수 컴파일) : 다음

에서 :

당신은

[AttributeUsage(AttributeTargets.Property)] 
class CalculatedByAttribute: Attribute 
{ 
    public string StaticMethodName {get; private set;} 
    public CalculatedByAttribute(string staticMethodName) 
    { 
     StaticMethodName = staticMethodName; 
    } 
} 

등으로 재산을 속성 것, 더 편리합니다 귀하의 방법, 귀하의 속성을 속성에 있다면, 당신은 정적 속성 값을 얻을 귀하의 쿼리에 사용합니다. 뭔가 따라 :

public static object ExecuteLinqMethod<T>(IQueryable<T> q, string Field, string Method) 
{ 
    var propInfo = typeof(T).GetProperty(Field); 
    LambdaExpression exp; 
    var myAttr = propInfo.GetCustomAttributes(typeof(CalculatedByAttribute), true).OfType<CalculatedByAttribute>().FirstOrDefault(); 
    if (myAttr != null) 
     exp = (LambdaExpression)typeof(T).GetField(myAttr.StaticMethodName, BindingFlags.Static | BindingFlags.Public).GetValue(null); 
    else 
    { 
     var param = Expression.Parameter(typeof(T), "p"); 
     Expression prop = Expression.Property(param, Field); 
     exp = Expression.Lambda(prop, param); 
    } 

    Type[] types = new Type[] { q.ElementType, exp.Body.Type }; 
    var mce = Expression.Call(typeof(Queryable),Method,types,q.Expression,exp); 

    return q.Provider.Execute(mce); 
} 
+0

고마워요! 매핑 된 속성을 계산할 때 작동하지만 매핑 된 필드와 계산 된 필드를 기반으로하는 계산 방법을 알지 못합니다. 중첩 된 식을 사용하려고하면 'LINQ 표현식 노드 유형'호출 '이 LINQ to Entities에서 지원되지 않습니다.'오류가 발생합니다. '예를 들어 나는이 같은 시도 : [CalculatedBy ("calculatedExpression1")] 공공 INT의 calculated1 {얻을 {calculatedExpression1.Compile를 (반환) (이); }} public static Expression > calculatedExpression1 = s => s.a * calculatedExpression.Compile() (s); –

+0

당신은 저였습니까? 2009 년은 오래 전 이었지만 그런 기사를 쓰는 것을 기억하지 않습니다. Microsoft 직원 인 Matt Warren은 그날의 일에 관한 기사를 몇 편 썼습니다. 어쩌면 당신은 그 중 한 명을 생각하고 있을까요? –

+0

@AdamBubula : 좀 더 복잡한 시나리오를 구성해야하는 경우,이 답을 체크 아웃 : http://stackoverflow.com/questions/29448432/pass-expression-parameter-as-argument-to-another-expression/29471092#29471092 – MBoros