使用 IQueryable 进行反射

发布于 2024-11-09 12:14:13 字数 1161 浏览 0 评论 0原文

我正在尝试为 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 来解决这个问题,但随后我在扩展方法中检索数据,但这不是我想要的。

这个问题能解决吗?

I'm playing around and trying to make an extension method for IQueryable that sorts it by an arbitrary property of a object.

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;
}
}

I get this error when a call the method. I guess it has to do with the IQueryable hasn't executed and retrieved any objects yet.

LINQ to Entities does not recognize the method System.Object GetValue(System.Object, System.Object[]), and this method cannot be translated into a store expression.

I can solve it by executing ToList on the IQueryable but then I retrieve the data in the extension method and that is not what I want.

Can this be solved?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

微凉徒眸意 2024-11-16 12:14:13

当您对 IQueryable<> 执行 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);
}

LINQ to Entities tries to run your queries in the database when you do a LINQ operation on an IQueryable<>. In your case "asc", you do query.OrderBy, which LINQ to Entities interprets as "transform this to SQL", and it fails since you use reflection calls, which it doesn't know how to convert to SQL.

You could do query.AsEnumerable().OrderBy(...). One effect of this is that as the OrderBy operation starts running, the rest of the query will execute in order for the data to be provided.

Rather than use these reflection tricks, you could get by simply by using the OrderBy and OrderByDescending methods, designed to take a delegate to pull the sort value out. (items.OrderBy(item => item.Property)). What you're missing is the ability to specify ascending or descending within the same method, but I would simply do a pair of methods like:

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文