4

Как я могу генерировать следующее с помощью деревьев выражений ...Создание динамических Выберите с помощью Expression Trees

var people = context.Set<Person>(); 
var transactions = context.Set<FinancialTransaction>(); 

var dataview = people.Where(p => p.LastName == "Smith"); 

var selection = dataview 
     .Select(p => new 
     { 
      FirstName = p.FirstName, 
      LastName = p.LastName, 
      LastTransaction = 
       transactions 
        .Where(t => t.AuthorizedPersonId == p.Id) 
        .Max(t => t.TransactionDateTime) 
     }); 

gReport.AutoGenerateColumns = true; 
gReport.DataSource = selection.ToList(); 
gReport.DataBind(); 

Я пытаюсь использовать решение LinqRuntimeTypeBuilder, что Итан Браун provided here но борется с тем, как создать выражение для подзапрос LastTransaction и способ привязки запроса к GridView.

Это то, что я до сих пор ...

var people = context.Set<Person>(); 
var transactions = context.Set<FinancialTransaction>(); 

var dataview = people.Where(p => p.LastName == "Smith"); 

var dynamicFields = new Dictionary<string, Type>(); 
dynamicFields.Add("FirstName", typeof(string)); 
dynamicFields.Add("LastName", typeof(string)); 
dynamicFields.Add("LastTransaction", typeof(DateTime?)); 

Type dynamicType = Rock.Data.LinqRuntimeTypeBuilder.GetDynamicType(dynamicFields); 

ParameterExpression sourceItem = Expression.Parameter(dataview.ElementType, "x"); 

// Is this right? if if so how do I bind it to the dynamic field???? 
Expression<Func<Person, DateTime>> lastTransactionSelect = a => transactions.Where(t => t.AuthorizedPersonId == a.Id && t.TransactionDateTime.HasValue).Max(t => t.TransactionDateTime.Value); 

var bindings = new List<MemberBinding>(); 
bindings.Add(Expression.Bind(dynamicType.GetField("FirstName"), Expression.Property(sourceItem, dataview.ElementType.GetProperty("FirstName")))); 
bindings.Add(Expression.Bind(dynamicType.GetField("LastName"), Expression.Property(sourceItem, dataview.ElementType.GetProperty("LastName")))); 
bindings.Add(Expression.Bind(dynamicType.GetField("LastTransaction"), ???)); 

Expression selector = Expression.Lambda(Expression.MemberInit(Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), sourceItem); 

var query = dataview.Provider.CreateQuery(
    Expression.Call(
     typeof(Queryable), 
     "Select", 
     new Type[] { dataview.ElementType, dynamicType }, 
    Expression.Constant(dataview), selector)).AsNoTracking(); 

// Can't bind directly to the query since it's a DBQuery object 
gReport.DataSource = ???; 

gReport.DataBind(); 

Как я могу создать выражение для суб-запроса, а затем и то, что это лучший способ, чтобы связать запрос к GridView?

+0

Просьба указать и пометить GUI, который вы используете. –

+0

Не знаете, что вы имели в виду под графическим интерфейсом? Вы имеете в виду IDE? Если это так, VS 20133. –

+0

Нет, вы привязываете его к чему-то правильному? WPF, WinForms, ASPX? –

ответ

4

После использования отражателя, чтобы оценить, как компилятор сгенерировал LINQ заявление, вот как я закончил создание выражения для подвыборки ...

ParameterExpression transactionParameter = Expression.Parameter(typeof(FinancialTransaction), "t"); 
MemberExpression authorizedPersonIdProperty = Expression.Property(transactionParameter, "AuthorizedPersonId"); 
MemberExpression transactionDateTime = Expression.Property(transactionParameter,"TransactionDateTime"); 

MethodInfo whereMethod = GetWhereMethod(); 
MethodInfo maxMethod = GetMaxMethod(); 

var personIdCompare = new Expression[] { 
    Expression.Constant(transactions), 
    Expression.Lambda<Func<FinancialTransaction, bool>>(Expression.Equal(authorizedPersonIdProperty, Expression.Convert(idProperty, typeof(int?))), new ParameterExpression[] { transactionParameter }) 
}; 
var transactionDate = Expression.Lambda<Func<FinancialTransaction, DateTime?>>(transactionDateTime, new ParameterExpression[] { transactionParameter }); 
var lastTransactionDate = Expression.Call(null, maxMethod, new Expression[] { Expression.Call(null, whereMethod, personIdCompare), transactionDate }); 

... 

bindings.Add(Expression.Bind(dynamicType.GetField("LastTransaction"), lastTransactionDate)); 


... 


private MethodInfo GetWhereMethod() 
{ 
    Func<FinancialTransaction, bool> fake = element => default(bool); 
    Expression<Func<IEnumerable<FinancialTransaction>, IEnumerable<FinancialTransaction>>> lamda = list => list.Where(fake); 
    return (lamda.Body as MethodCallExpression).Method; 
} 

private MethodInfo GetMaxMethod() 
{ 
    Func<FinancialTransaction, DateTime?> fake = element => default(DateTime?); 
    Expression<Func<IEnumerable<FinancialTransaction>, DateTime?>> lamda = list => list.Max(fake); 
    return (lamda.Body as MethodCallExpression).Method; 
} 
0

Я знаю, что ваш главный вопрос заключается в создании динамического дерева выражений linq, но я мог бы помочь с вашим вторичным вопросом о привязке Queryable к сетке.

EDIT: К сожалению, я на самом деле пробовал это и делает OfType < объект> генерируется исключение Casting, так что здесь что-то, что действительно будет работать

var query = dataview.Provider.CreateQuery(
    Expression.Call(
     typeof(Queryable), 
     "Select", 
     new Type[] { dataview.ElementType, dynamicType }, 
    Expression.Constant(dataview), selector)).AsNoTracking(); 

// enumerate thru the query results and put into a list 
var listResult = new List<object>(); 
var enumerator = query.GetEnumerator(); 
while (enumerator.MoveNext()) 
{ 
    reportResult.Add(enumerator.Current); 
} 

gReport.DataSource = listResult; 

gReport.DataBind(); 
+0

Спасибо, Майк, который помогает привязывать к GridView, но да, мой главный вопрос и самая большая борьба - это как построить дерево выражений (я знаю, что я не должен был задавать два вопроса в одном, извините). –

Смежные вопросы