2016-09-27 8 views
1
은 내가 필요한 것은 Linq.Expressions를 통해이 쿼리를 표현하는 것입니다

이의 구현은 GROUPBY 쿼리

IQueryable<Document> data = db.Documents; 

ParameterExpression pe = Expression.Parameter(typeof(Document), "doc"); 

Expression groupBy = Expression.Call(
    typeof(Queryable), 
    "GroupBy", 
    new Type[] { typeof(Document), typeof(int) }, 
    data.Expression, 
    Expression.Lambda(Expression.Constant(1), pe)); 

ParameterExpression peg = Expression.Parameter(typeof(IGrouping<int, Document>), "group"); 

Expression select = Expression.Call(
    typeof(Queryable), 
    "Select", 
    new Type[] { typeof(IGrouping<int, Document>), typeof(int) }, 
    groupBy, 
    Expression.Lambda(Expression.Property(peg, "Key"), peg)); 

foreach (var item in data.Provider.CreateQuery(select)) { ... } 

했다 :

db.Documents.GroupBy(a => 1).Select(b => b.Key }); 

완벽하게 작동합니다. 이제 그룹 키에 액세스하는 대신 합계를 집계합니다.

그것이 나를 위해 까다로운 곳입니다. 나는 이런 식으로 뭔가를 생각하고 있었다 :

IEnumerable<Document>.Sum<Document>(Func<Document, decimal> selector) 

을 위해 동안 :

db.Documents.Sum(a => a.Amount) 

내가 할

ParameterExpression pe1 = Expression.Parameter(typeof(Document), "other"); 

Expression sum = Expression.Call(
    typeof(Queryable), 
    "Sum", 
    new Type[] { typeof(Document) }, 
    peg, 
    Expression.Lambda(Expression.Property(pe1, "Amount"), pe1)); 

을 또한, Sum 함수에 대한

...b.Sum(c => c.Amount) 

에 인텔리는 서명이 있습니다 :

IQueryable<Document>.Sum<Document>(Expression<Func<Document, decimal>> selector) 

Selector는 한 버전에서는 Func이고 다른 버전에서는 Func입니다. Linq 표현식에서 Func 처리 방법을 모르겠습니다. 어쩌면 인텔리 센스가 틀렸을까요?

집계 소스에 대한 표현이 가장 큰 문제입니다. 보고 :

...b.Sum(c => c.Amount) 

나는 b는 ('선택'의 ParameterExpression를) IGrouping해야 가정 것이고, 그 합계의 소스해야하지만, 그것은 컴파일되지 않습니다. 그 밖의 무엇을 시도 해야할지 모르겠습니까?

Expression Select = Expression.Call(
    typeof(Queryable), 
    "Select", 
    new Type[] { typeof(IGrouping<int, Document>), typeof(decimal?) }, 
    GroupBy, 
    Expression.Lambda(sum, peg)); 

하지만도 실패로 인해 '합'표현의이 지점에 도달 할 수 없습니다 여기

은 선택 식을 같이하는 방법 마지막이다.

모든 포인터가 감사하겠습니다.

감사합니다.

+0

그냥 궁금 그룹의 포인트는 상수로 무엇 : 그와

는 샘플 쿼리 식을 만들어 보자 말했다되고? – dasblinkenlight

+1

동일한 데이터에 대해 동시에 여러 집계가 필요하므로 단일 데이터베이스를 사용하는 유일한 방법입니다. –

답변

1

Intellisense는 정상입니다.참조하자

db.Documents.GroupBy(a => 1).Select(b => b.Sum(c => c.Amount) }); 

(1) db.Documents 타입이 IQueryable<Document>
(2) a 타입이 Document
(3) db.Documents.GroupBy(a => 1) 타입이 IQueryable<IGrouping<int, Document>>
(4) b 타입 IGrouping<int, Document>이다 which in turn isIEnumerable<Document>
(5) c 유형은 Document

이며 이는 GroupBySelect 방법은 Queryable이고, SumEnumerable이다.

MethodCall 표현에서 Func<...>Expression<Func<...>>을 구별하는 방법은 무엇입니까? 규칙은 간단합니다. 두 경우 모두 Expression.Lambda<Func<...>>을 사용하여 Expression<Func<...>>을 생성 한 다음 호출에 Func<...>이 필요하면 직접 전달하고 Expression<Func<...>>을 예상하면 메서드를 Expression.Quote으로 바꿉니다.

var query = db.Documents.AsQueryable(); 
// query.GroupBy(a => 1) 
var a = Expression.Parameter(typeof(Document), "a"); 
var groupKeySelector = Expression.Lambda(Expression.Constant(1), a); 
var groupByCall = Expression.Call(typeof(Queryable), "GroupBy", 
    new Type[] { a.Type, groupKeySelector.Body.Type }, 
    query.Expression, Expression.Quote(groupKeySelector)); 
// c => c.Amount 
var c = Expression.Parameter(typeof(Document), "c"); 
var sumSelector = Expression.Lambda(Expression.PropertyOrField(c, "Amount"), c); 
// b => b.Sum(c => c.Amount) 
var b = Expression.Parameter(groupByCall.Type.GetGenericArguments().Single(), "b"); 
var sumCall = Expression.Call(typeof(Enumerable), "Sum", 
    new Type[] { c.Type }, 
    b, sumSelector); 
// query.GroupBy(a => 1).Select(b => b.Sum(c => c.Amount)) 
var selector = Expression.Lambda(sumCall, b); 
var selectCall = Expression.Call(typeof(Queryable), "Select", 
    new Type[] { b.Type, selector.Body.Type }, 
    groupByCall, Expression.Quote(selector)); 
// selectCall is our expression, let test it 
var result = query.Provider.CreateQuery(selectCall); 
+0

상세한 답변을 주신 이반 감사인은 합계가 Enumerable 및 Queryable로 정의되었음을 깨닫지 못했습니다. 내 눈앞에있었습니다. . –