Reputation: 25
When using Entity Framework 5, why would this work?
var query = Categories.Select(c => new
{
Products = c.Products.OrderBy(p => p.Name)
});
While this won't?
Func<Product, string> selector = p => p.Name;
var query = Categories.Select(c => new
{
Products = c.Products.OrderBy(selector)
});
The thrown exception is: Unsupported overload used for query operator 'OrderBy'.
Upvotes: 2
Views: 441
Reputation: 177163
Making selector
an Expression<Func<Product, string>>
won't work directly and will not compile because c.Products
is not an IQueryable<T>
. It is just a collection type implementing only IEnumerable<T>
. Enumerable.OrderBy
does not accept an expression as parameter, only a delegate.
But EF still needs an expression, not a delegate. The trick is to use AsQueryable()
on the navigation collection:
Expression<Func<Product, string>> selector = p => p.Name;
var query = Categories.Select(c => new
{
Products = c.Products.AsQueryable().OrderBy(selector)
});
Upvotes: 0
Reputation: 2732
Here is a working example of the query working okay and not causing a problem. I skipped the database for simplicity and went directly to an in-memory object, which is probably why it's working for me. I think Honza is right, that this is an issue related to the ORM layer. You can run the below example
Here is an example for 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; }
}
// Define other methods and classes here
Here is a version for 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; }
}
}
}
Upvotes: 0
Reputation: 10957
The query
variable name hints that you may be using Entity Framework, LINQ to SQL or some other IQueryable<T>
based API. You are passing the selector
as Func
. The underlying query provider cannot translate Func
to SQL (or any other language, whatever you may be using).
Change the type of selector
to Expression<Func<Product, string>>
(the rest can remain the same, because lambda expressions can be interpreted either as a delegate or an expression tree. That's why you can's use var
with lambdas - the compiler just can't tell if you want the lambda to be a delegate or expression tree) and see if that fixes your problem. You haven't provided enough information for me to be 100% sure, but it should. The OrderBy
overloads accepting an Expression
should be able to walk the expression tree and translate it to the underlying query. It's somewhat a guess, but I hope it helps you.
Upvotes: 6