在投射匿名类型时,OrderBy选择器失败

时间:2013-07-21 22:12:07

标签: c# linq entity-framework

使用Entity Framework 5时,为什么会这样?

var query = Categories.Select(c => new 
    { 
        Products = c.Products.OrderBy(p => p.Name) 
    });

虽然这不会?

Func<Product, string> selector = p => p.Name;
var query = Categories.Select(c => new 
    { 
        Products = c.Products.OrderBy(selector) 
    });

引发的异常是:用于查询运算符'OrderBy'的不支持的重载。

3 个答案:

答案 0 :(得分:6)

query变量名称暗示您可能正在使用Entity Framework,LINQ to SQL或其他基于IQueryable<T>的API。您将selector作为Func传递。基础查询提供程序无法将Func转换为SQL(或任何其他语言,无论您使用何种语言)。

selector的类型更改为Expression<Func<Product, string>>(其余的可以保持不变,因为lambda表达式可以解释为委托或表达式树。这就是为什么你可以使用{{1}使用lambdas - 编译器无法判断您是否希望lambda成为委托或表达式树)并查看是否可以解决您的问题。你没有提供足够的信息让我100%肯定,但它应该。接受var的{​​{1}}重载应该能够遍历表达式树并将其转换为基础查询。这有点猜测,但我希望它可以帮助你。

答案 1 :(得分:0)

以下是查询正常工作并且不会导致问题的工作示例。为简单起见,我跳过数据库,直接转到内存中的对象,这可能就是为什么它对我有用。我认为Honza是对的,这是与ORM层相关的问题。您可以运行以下示例

这是linqpad的一个例子:

void Main()
{

        var Categories = new List<Category>() { new Category { CategoryName = "CatName", Products = new List<Product>() { new Product { Name = "ProductName1" } } } };

        Func<Product, string> selector = p => p.Name;
        var sb = new StringBuilder();
        var query = Categories.Select(c => new
        {
            Products = c.Products.OrderBy(selector)
        });
        foreach (var x in query)
        {
            sb.AppendLine(x.Products.First().Name);
        }

        Console.WriteLine(sb.ToString());
        Console.Read();


    }


    public class Product
    {
        public string Name { get; set; }
    }

    public class Category
    {
        public string CategoryName { get; set; }
        public List<Product> Products { get; set; }
    }

//在此定义其他方法和类

以下是visual studio console app的版本:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            var Categories = new List<Category>() { new Category { CategoryName = "CatName", Products = new List<Product>() { new Product { Name = "ProductName1" } } } };
        Func<Product, string> selector = p => p.Name;
        var sb = new StringBuilder();
        var query = Categories.Select(c => new
        {
            Products = c.Products.OrderBy(selector)
        });
        foreach (var x in query)
        {
            sb.AppendLine(x.Products.First().Name);
        }

        Console.WriteLine(sb.ToString());
        Console.Read();


    }


    public class Product
    {
        public string Name { get; set; }
    }

    public class Category
    {
        public string CategoryName { get; set; }
        public List<Product> Products { get; set; }
    }
}

}

答案 2 :(得分:0)

使selector成为Expression<Func<Product, string>>将无法直接生效,因为c.Products不是IQueryable<T>而无法编译。它只是一个仅实现IEnumerable<T>的集合类型。 Enumerable.OrderBy不接受表达式作为参数,只接受委托。

但EF仍然需要一个表达,而不是代表。诀窍是在导航集合上使用AsQueryable()

Expression<Func<Product, string>> selector = p => p.Name;
var query = Categories.Select(c => new 
{ 
    Products = c.Products.AsQueryable().OrderBy(selector) 
});