使用表达式树构建动态选择

 手机用户2502936971 发布于 2023-02-12 14:23

如何使用表达式树生成以下内容...

var people = context.Set();
var transactions = context.Set();

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 在这里提供的LinqRuntimeTypeBuilder解决方案,但在如何为LastTransaction子查询创建表达式以及如何将查询绑定到GridView方面苦苦挣扎.

这就是我到目前为止......

var people = context.Set();
var transactions = context.Set();

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

var dynamicFields = new Dictionary();
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> lastTransactionSelect = a => transactions.Where( t => t.AuthorizedPersonId == a.Id && t.TransactionDateTime.HasValue ).Max( t => t.TransactionDateTime.Value );

var bindings = new List();
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的最佳方法是什么?

1 个回答
  • 在使用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;
    }
    

    2023-02-12 14:26 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有