如何使用表达式树生成以下内容...
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();
我正在尝试使用Ethan Brown provided here的LinqRuntimeTypeBuilder解决方案,但在如何为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 :(得分:6)
使用Reflector评估编译器如何生成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;
}
答案 1 :(得分:0)
我知道您的主要问题是关于构建动态linq表达式树,但我可以帮助解决有关将Queryable绑定到网格的第二个问题。
编辑:对不起,我实际上尝试了这个并做了OfType&lt;对象&gt;生成一个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();