简体   繁体   English

如何使用表达式树对IQueryable对象动态排序?

[英]How to sort an IQueryable object dynamically with an expression tree?

Currently I have a custom datagridview where the user can browse true it's pages with buttons like next, previous, first and last. 目前,我有一个自定义的datagridview,用户可以使用下一个,上一个,第一个和最后一个按钮浏览真实的页面。

In the generic part of the code I have the following IQueryable object: IQueryable iqRetVal = iqData; 在代码的通用部分中,我具有以下IQueryable对象: IQueryable iqRetVal = iqData; . Its contents is dynamically filled by other forms and it could contain for example users and the next time companies (So there is no way of knowing beforehand what will be in it.). 它的内容由其他形式动态填充,并且可能包含例如用户和下一次公司(因此,无法预先知道其中的内容。)。

This is the code for iqData : 这是iqData的代码:

IQueryable iqData = null;
public IQueryable Data //this is how iqData is filled.
{
    get { return iqData; }
    set
    {
        iqData = value;
        RefreshDataGridView();
    }
}

Now I know what the user previously clicked on based on 2 variables: 现在,我知道用户先前基于2个变量单击了什么:

private SortOrder sortOrder; //The sort order like ascending or descending
private DataGridViewColumn dataGridViewColumn; the column that was sorted on.

This is the error message that my code gives: 这是我的代码给出的错误消息:

No generic method OrderByDescending in type System.Linq.Queryable is compateble with the given typearguments and arguments. System.Linq.Queryable类型中的任何通用方法OrderByDescending都不能与给定的typearguments和arguments兼容。 No typearguments must ge given if the method is not generic. 如果该方法不是泛型的,则不必给出任何类型参数。

The code itself: 代码本身:

try
{
    if (dataGridViewColumn != null)
    {
        var propName = dataGridViewColumn.DataPropertyName;
        ParameterExpression param = null;

        foreach (var item in iqRetVal)
        {
            if (item != null)
            {
                param = Expression.Parameter(item.GetType(), string.Empty);
                break;
            }
        }
        MemberExpression property = Expression.PropertyOrField(param, propName);
        LambdaExpression sort = Expression.Lambda(property, param);

        if (sortOrder == SortOrder.Descending)
        {
            iqRetVal = iqRetVal.Provider.CreateQuery(Expression.Call(typeof(Queryable), "OrderBy", new Type[] { iqRetVal.ElementType }, iqRetVal.Expression, Expression.Quote(sort)));
        }
        else
        {
            iqRetVal = iqRetVal.Provider.CreateQuery(Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { iqRetVal.ElementType }, iqRetVal.Expression, Expression.Quote(sort)));
        }

    }
    else { }
}
catch(Exception ex)
{
    MessageBox.Show(ex.Message);
    System.Diagnostics.Debug.WriteLine(ex.Message);
}

What exactly am I missing to make my code work? 我到底缺少什么来使我的代码正常工作? Because I have searched for a long time but it seems like most answers don't offer the answer I'm looking for. 因为我已经搜索了很长时间,但似乎大多数答案都没有提供我要的答案。

The method call causing problems is this: 导致问题的方法调用是这样的:

Expression.Call(typeof(Queryable), "OrderBy", new Type[] { iqRetVal.ElementType }, iqRetVal.Expression, Expression.Quote(sort));

Looking at the documentation for this overload of CreateQuery we can see that the first parameter is the type that contains the static method, the second is the method name, the third is the generic parameters needed by that method and the subsequent items are the parameters to the method. 查看有关CreateQuery重载文档,我们可以看到第一个参数是包含静态方法的类型,第二个是方法名称,第三个是该方法所需的通用参数,后续项是方法。

The OrderBy method does exist on Queryable so our first two paramters are good. OrderBy方法确实存在于Queryable因此我们的前两个参数很好。 If we look at this method though then we see that it has two generic parameters: OrderBy<TSource,TKey> . 如果我们看一下这个方法,那么我们会看到它有两个通用参数: OrderBy<TSource,TKey> Currently we are only passing one type. 目前,我们只传递一种类型。 This makes sense of the error message which says the type arguments are incorrect. 这使错误消息变得有意义,该错误消息指出类型参数不正确。

So our first type is the type of the Queryable which we are correctly getting as iqRetVal.ElementType . 因此,我们的第一个类型是Queryable的类型,我们可以正确地将其获取为iqRetVal.ElementType The second is the type of key that our sort selector returns. 第二个是我们的排序选择器返回的键的类型。 This can be found using sort.ReturnType . 可以使用sort.ReturnType找到。

So this would then make the method call look like this: 因此,这将使方法调用如下所示:

Expression.Call(typeof(Queryable), "OrderBy", new Type[] { iqRetVal.ElementType, sort.ReturnType }, iqRetVal.Expression, Expression.Quote(sort))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM