2011-11-16 4 views
0

je les suivantes (très simplifiée) domaine:Query Propriétés NHibernate avec LINQ

public class Product 
{ 
    public virtual int Id { get; set; } 
    public virtual string Description { get; set; } 
    public virtual IList<Category> Categories { get; set; } 
} 

public class Category 
{ 
    public virtual int Id { get; set; } 
    public virtual string Description { get; set; } 
} 

La collection many-to-many est mis en correspondance en utilisant le code XML suivant:

<bag name="Categories" table="ProductsCategories"> 
    <key column="ProductID" /> 
    <many-to-many column="CategoryID" class="Category" /> 
</bag> 

Quand je chargement de mes catégories en utilisant la propriété du produit tout fonctionne correctement:

Product product = ProductRepository.Find(1); 
var categories = product.Categories; 

Le problème est que lorsque je tente de filtre ma collection, par exemple:

Product product = ProductRepository.Find(1); 
var categories = product.Categories.Where(c => c.SomeProperty == someValue); 

La requête est pas exécutée sur la base mais il utilise LINQ aux objets pour filtrer le résultat! Est-il possible de résoudre ce problème sans utiliser HQL et sans avoir besoin de mapper une nouvelle entité appelée par exemple "OrderDetail"?

+0

Ce n'est pas une réponse valide, mais ça marche si vous. Catégories var = product.Categories.ToList() Où (c => c.SomeProperty == someValue); – 4imble

+0

Oui, mais NHibernate chargera la totalité de la collection à partir de la base de données, puis exécutera le filtre en utilisant LINQ to Objects. – StockBreak

+0

À quoi ressemble votre méthode repository.Find (#)? – 4imble

Répondre

0

Le problème est que Categories est déclarée comme

IList<Category> Categories 

Cela signifie que votre requête utilisera Enumerable.Where au lieu de Queryable.Where.

Je m'attendrais à ce que NHibernate supporte une autre interface implémentant IQuerable<T>, que vous utiliseriez pour déclarer votre propriété, par ex.

public virtual IQueryableList<Category> Categories { get; set; } 

Je ne l'ai pas utilisé NHibernate dans la colère, alors je ne sais pas ce que le type est en fait, mais c'est ce que vous devriez rechercher.

+0

Merci pour votre réponse. Le problème est que je ne voudrais pas exposer mes propriétés comme IQueryable. Devrais-je vraiment faire ça? – StockBreak

+0

@StockBreak: Si vous * n'exposez pas "IQueryable ", comment voulez-vous que la requête soit traduite en SQL? –

+0

Je voudrais éviter d'exposer publiquement une propriété IQueryable puisque je cache toujours les opérations LINQ dans les méthodes du référentiel, puis retourne simplement les propriétés IList ou IEnumerable. Je viens d'essayer ceci et j'obtiens une erreur lors du chargement des commandes: _Unable pour lancer l'objet de type 'NHibernate.Collection.Generic.PersistentGenericBag'1 [MyDomain.Entities.OrderDetail]' pour taper 'System.Linq.IQueryable'1 [MyDomain .Entities.OrderDetail] '_. – StockBreak

1

Vous devez interroger le category, pas les catégories de product. (Vous pouvez faire ce que vous vouliez initialement avec ISession.Filter, mais cela n'a pas pris LINQ la dernière fois que j'ai regardé).

par exemple.

from category in session.Linq<Category> 
where category.Products.Contains(product) and category.SomeProperty == someValue 
select category 
+0

Salut David, ma relation est malheureusement beaucoup-à-plusieurs et pas un-à-plusieurs. Mon objet 'Category' n'a pas de propriété' Product'. – StockBreak

+0

@StockBreak - J'ai changé la requête pour utiliser 'Contains' pour la propriété' Category.Products'. Si la catégorie n'a pas de propriété 'Products', ajoutez-en une chargée paresseuse. –

+0

Malheureusement, cela ne fonctionne pas car 'category.Products' sera évalué en premier, puis' Contains (product) 'sera exécuté avec LINQ to Objects. – StockBreak