2013-07-21 65 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