与IQueryable的反思

时间:2011-05-24 07:08:50

标签: reflection iqueryable propertyinfo

我正在玩并尝试为IQueryable创建一个扩展方法,用对象的任意属性对其进行排序。

public static class IQueryableExtender

{

public static IQueryable<TSource> Sort<TSource>(this IQueryable<TSource> query, string orderProperty, string sortDirection = "asc")      
{

    var elementType = query.ElementType;

    var propertyInfo = elementType.GetProperty(orderProperty);
    if (propertyInfo == null)
    {
         throw new ArgumentException(string.Format("{0} is not a property on {1}", orderProperty, elementType.Name));
    }


    switch (sortDirection.ToLower())
    {
       case "asc":
       case "ascending":
           return query.OrderBy(x => propertyInfo.GetValue(x, null));
           break;
       case "desc":
       case "descending":
           return query.OrderByDescending(x => propertyInfo.GetValue(x, null));
           break;
    }

    return query;
}
}

调用方法时出现此错误。我想这与IQueryable有关,还没有执行和检索任何对象。

LINQ to Entities无法识别方法System.Object GetValue(System.Object, System.Object[]),并且此方法无法转换为商店表达式。

我可以通过在IQueryable上执行ToList来解决它,但后来我在扩展方法中检索数据,这不是我想要的。

这可以解决吗?

1 个答案:

答案 0 :(得分:2)

当您在IQueryable&lt;&gt;上执行LINQ操作时,LINQ to Entities会尝试在数据库中运行您的查询。在你的case "asc"中,你执行query.OrderBy,它将LINQ to Entities解释为“将其转换为SQL”,并且由于你使用了反射调用而失败,因为它不知道如何转换为SQL。

你可以做query.AsEnumerable()。OrderBy(...)。这样做的一个结果是,当OrderBy操作开始运行时,将执行查询的其余部分以便提供数据。

您可以通过简单地使用OrderBy和OrderByDescending方法来获取,而不是使用这些反射技巧,这些方法旨在让委托将抽样值拉出来。 (items.OrderBy(item => item.Property))。你缺少的是在同一个方法中指定升序或降序的能力,但我只想做一对方法,如:

public static IOrderedQueryable<TSource> OrderByAscDesc<TSource, TKey>(
    this IQueryable<TSource> source,
    Expression<Func<TSource, TKey>> keySelector, bool isAsc
) {
    return (isAsc ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector);
}

public static IOrderedQueryable<TSource> OrderByAscDesc<TSource, TKey>(
    this IQueryable<TSource> source,
    Func<TSource, TKey> keySelector, bool ascDesc
) {
    return (isDesc ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector);
}