2013-07-21 39 views
2

使用实体框架5时,为什么这会起作用?OrderBy选择器在投影匿名类型时失败

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'的不支持的重载。

+0

告诉我..没有'产品= c.Products.ToList()排序依据(选择)'的作品吗? –

+0

@SimonWhitehead:不,它不起作用,同样的例外。无论如何,即使调用ToList()工作,当产品在订购之前被过滤时,这也不是一个好的解决方案,因为订购将发生在内存中。 – user2604373

+1

这对我来说很好。你能提供一个可以抛出这个异常的工作示例吗? –

回答

0

制作selectorExpression<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) 
}); 
+0

已经尝试过。同样的例外。 – user2604373

+0

@ user2604373:你在使用什么数据库? – Slauma

+0

我在SQL Server 2012 Enterprise和SQL Azure上试过它。 – user2604373

6

query变量名称提示您可能正在使用实体框架,LINQ to SQL或其他一些基于IQueryable<T>的API。您通过selector作为Func。底层查询提供程序无法将Func转换为SQL(或任何其他语言,无论您使用哪种语言)。

变化selectorExpression<Func<Product, string>>类型(其余的可以保持不变,因为lambda表达式可以解释无论是作为委托或表达式目录树这就是为什么你可以的使用var与lambda表达式 - 编译器就不能告诉如果你想让lambda成为一个委托或表达式树),看看是否解决了你的问题。你没有提供足够的信息让我百分之百地确定,但它应该。接受ExpressionOrderBy重载应该能够遍历表达式树并将其转换为基础查询。这有点猜测,但我希望它可以帮助你。

+0

谢谢。在发布此问题之前,我尝试了Expression >。它不起作用。 – user2604373

+0

@ user2604373这意味着您提供的特定表达式无法由查询提供程序进行分析。如果不知道实际的表达是什么,那我们真的没有什么可说的了。 – Servy

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的控制台应用程序版本:

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

}

+0

是的,它以这种方式工作,但是当您使用实体框架进行操作时,它会抛出异常。我将编辑我的问题并提及我正在使用实体框架。谢谢丹。 – user2604373