I have an IQueryable<Product>
that needs to be sorted by Name
. Each Product
has an IQueryable<Category>
that also needs to be sorted by Name
. I'm having a hard time expressing this in Linq. I could loop through the products and sort each category list, but it seems messy. Hoping a Linq ninja has a smarter solution.
My Product
class looks like:
public class Product {
public string Name { get; set; }
public IQueryable<Category> Categories { get; set; }
}
My Category
class looks like:
public class Category {
public string Name { get; set; }
}
Currently, I'm doing this:
var myProducts = products.Or开发者_开发知识库derBy(x => x.Name).Select(x => new Product {
Name = x.Name,
Categories = x.Categories(y => y.Name)
});
The trouble is, when using something like NHibernate, this creates new Product objects, essentially disconnecting the product from the NH session.
You don't want to modify the Product
object in any way that could affect persistence and you don't want to create new Product
instances.
So add this to Product
class:
public IOrderedEnumerable<Category> CategoriesOrderedByName
{
get { return this.Categories.OrderBy(y => y.Name); }
}
And use product.CategoriesOrderedByName
instead when you need the sorted version in your UI code.
Without this anyone using your class has no expectation that the Category
objects are sorted in any way. With this you are being explicit in informing consumers of your class what to expect and that you intend to always return them in a sorted order. You can also use IOrderedEnumerable<>
as the return type to make allow further sub-sorting using ThenBy()
.
Maybe this is what you want? You do not get a list of products that each has a list of categories, however. That's impossible using LINQ because you can not alter a collection using LINQ, you can only make a new collection from an existing one (in my example p.Categories
is the existing collection, SortedCategories
the new one).
from p in products
orderby p.Name
select new
{
Product = p,
SortedCategories = from c in p.Categories
orderby c.Name
select c
}
You say you have IQueryable
's. Does that mean that you are querying against a database using this LINQ statement? I'm not sure how well this transforms to SQL (performance-wise).
Why not just sort the enumerable in place?
products = products.OrderBy(x => x.Name);
products.ToList().ForEach(x => x.Categories = x.Categories.OrderBy(y => y.Name));
As others have stated, this may perform poorly if you're connected.
If you want to enumerate over the Product
objects in sorted order and within each Product
you want the Categories
in sorted order, you could do something like this.
var sorted = products
.Select(
p => new
{
Product = p,
Categories = p.Categories.OrderBy(c => c.Name)
}
)
.OrderBy(x => x.Product.Name);
It looks like this is basically what Ronald has, only without using LINQ syntax.
精彩评论