开发者

Sorting collection and sub-collection at the same time

开发者 https://www.devze.com 2023-01-13 17:37 出处:网络
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 Lin

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消