2010-08-31 6 views
1

J'ai un IQueryable<Product> qui doit être trié par Name. Chaque Product a un IQueryable<Category> qui doit également être trié par Name. J'ai du mal à l'exprimer à Linq. Je pourrais passer en revue les produits et trier chaque liste de catégorie, mais il semble malpropre. Espérer un ninja Linq a une solution plus intelligente.Trier la collection et la sous-collection en même temps

Mon Product classe ressemble à:

public class Product { 
    public string Name { get; set; } 
    public IQueryable<Category> Categories { get; set; } 
} 

Ma classe Category ressemble:

public class Category { 
    public string Name { get; set; } 
} 

Actuellement, je suis en train de faire ceci:

var myProducts = products.OrderBy(x => x.Name).Select(x => new Product { 
    Name = x.Name, 
    Categories = x.Categories(y => y.Name) 
}); 

Le problème est, quand en utilisant quelque chose comme NHibernate, cela crée de nouveaux objets de produit, essentiellement disque connecter le produit de la session NH.

+0

Je ne pense pas que ce soit désordonné. Le tri des produits et le tri des catégories sont deux opérations totalement différentes sur le plan conceptuel; ce n'est pas mal de les séparer en code. – mquander

+1

Quel est l'état final que vous essayez d'atteindre? Une liste ? – arootbeer

+0

J'ai mis à jour ma question. –

Répondre

1

Vous ne souhaitez pas modifier l'objet Product d'une manière susceptible d'affecter la persistance et vous ne souhaitez pas créer de nouvelles instances Product.

ajouter donc à cette Product classe:

public IOrderedEnumerable<Category> CategoriesOrderedByName 
{ 
    get { return this.Categories.OrderBy(y => y.Name); } 
} 

Et utiliser product.CategoriesOrderedByName place lorsque vous avez besoin de la version triée dans votre code d'interface utilisateur. Sans que quiconque utilisant votre classe ne s'attend à ce que les objets Category soient triés de quelque manière que ce soit. Avec cela, vous êtes explicite en informant les consommateurs de votre classe à quoi s'attendre et que vous avez l'intention de toujours les retourner dans un ordre trié. Vous pouvez également utiliser IOrderedEnumerable<> comme type de retour pour autoriser un sous-tri supplémentaire en utilisant ThenBy().

0

Peut-être que c'est ce que vous voulez? Cependant, vous n'avez pas la liste des produits qui ont chacun une liste de catégories. C'est impossible en utilisant LINQ parce que vous ne pouvez pas modifier une collection en utilisant LINQ, vous pouvez seulement faire une nouvelle collection à partir d'une collection existante (dans mon exemple p.Categories est la collection existante, SortedCategories la nouvelle).

from p in products 
orderby p.Name 
select new 
{ 
    Product = p, 
    SortedCategories = from c in p.Categories 
         orderby c.Name 
         select c 
} 

Vous dites que vous avez IQueryable « s. Cela signifie-t-il que vous interrogez une base de données à l'aide de cette instruction LINQ? Je ne suis pas sûr à quel point cela se transforme en SQL (performance-sage).

0

Pourquoi ne pas simplement trier l'énumérable en place?

products = products.OrderBy(x => x.Name); 
products.ToList().ForEach(x => x.Categories = x.Categories.OrderBy(y => y.Name)); 

Comme d'autres l'ont indiqué, cela peut mal fonctionner si vous êtes connecté.

0

Si vous souhaitez énumérer sur les objets Product dans l'ordre trié et dans chaque Product vous voulez le Categories dans l'ordre trié, vous pourriez faire quelque chose comme ceci.

var sorted = products 
    .Select(
     p => new 
     { 
      Product = p, 
      Categories = p.Categories.OrderBy(c => c.Name) 
     } 
    ) 
    .OrderBy(x => x.Product.Name); 

Il ressemble à ceci est essentiellement ce que Ronald a, seulement sans utiliser la syntaxe LINQ.

Questions connexes