2010-12-07 24 views
1

J'ai une entité qui ressemble à ceci:Comment faire un OfType <>(). Count() sur une collection hétérogène dans NHibernate?

public class Album 
{ 
    public virtual string Name { get; set; } 
    public virtual IEnumerable<Media> { get; set; } 

    public virtual IEnumerable<Picture> 
    { 
     get { return Media.OfType<Picture>(); } 
    } 

    public virtual IEnumerable<Video> 
    { 
     get { return Media.OfType<Video>(); } 
    } 

    public virtual IEnumerable<Audio> 
    { 
     get { return Media.OfType<Audio>(); } 
    } 
} 

Media est la classe de base abstraite et Picture, Video et Audio sont les sous-types de Media, de sorte que la collection IEnumerable<Media> est hétérogène.

J'ai un DTO pour Album qui ressemble à ceci:

public class AlbumDTO 
{ 
    public string Name { get; set; } 
    public int PictureCount { get; set; } 
    public int VideoCount { get; set; } 
    public int AudioCount { get; set; } 
} 

Si chaque chef d'accusation est rempli en faisant <collection>.Count();. Bien que ce code fonctionne très bien et je reçois le compte pour chaque type de support, le SQL généré est moins qu'idéal:

SELECT * FROM Media WHERE media.Album_id = 1 
SELECT * FROM Media WHERE media.Album_id = 2 
SELECT * FROM Media where media.Album_id = 3 

En d'autres termes, il est saisissant tous les Media d'abord de la base de données, puis effectuer la OfType<T>.Count() suite en mémoire. Le problème est, si je fais cela sur tous les Albums, il va sélectionner tous les Media de la base de données, ce qui pourrait potentiellement être des milliers d'enregistrements. De préférence, je voudrais voir quelque chose comme ça (j'utilise une table par hiérarchie mapping):

SELECT COUNT(*) FROM Media WHERE media.Album_id = 1 AND discriminator = 'Picture' 
SELECT COUNT(*) FROM Media WHERE media.Album_id = 1 AND discriminator = 'Video' 
SELECT COUNT(*) FROM Media WHERE media.Album_id = 1 AND discriminator = 'Note' 

Est-ce que quelqu'un sait comment je peux configurer NHibernate pour ce faire? Ou devrais-je modifier mon entité Album afin d'obtenir le comportement correct?

+0

publiez votre config. Tu utilises Fluent Nhibernate? – Aliostad

+0

J'utilise Fluent NHibernate avec automapping. C'est juste en utilisant les conventions par défaut. –

Répondre

2

Tout d'abord, votre code ne sera pas compilé; il vous manque le nom de propriété du IEnumerable<Media> (je suppose que c'est Media), et aussi des filtres. Deuxièmement, vous devez comprendre un peu ce qui se passe. De ce comportement, je suis sûr que vous avez mappé votre album avec une relation HasMany à Media. Par défaut, NH charge par défaut, donc lorsque vous récupérez l'album pour la première fois dans la BD, Media reçoit une référence à un objet NHibernate appelé PersistentBag. C'est simplement un espace réservé qui ressemble à un IEnumerable, et qui contient la logique pour remplir la liste réelle quand elle est réellement nécessaire. Tout ce qu'il peut faire est de tirer les enregistrements comme mappés dans le HBM lorsque sa méthode GetEnumerator() est appelée (et cela arrive dans pratiquement toutes les méthodes Linq). Ainsi, lorsque vous appelez OfType, vous ne travaillez plus avec un NHibernate IQueryable, qui peut construire une instruction SQL qui fait exactement ce que vous voulez. Au lieu de cela, vous demandez pour chaque élément de la liste que vous pensez avoir déjà, et NHibernate se conforme.

Vous avez quelques options si tout ce que vous voulez est le nombre. Le plus simple, si possible, est tout simplement de revenir à la session et demander une toute nouvelle requête sur l'album:

session.Linq<Album>().Where(a=>a.Id = 1).Select(a=>a.Media.OfType<Picture>()).Count(); 

Cela va construire directement une déclaration qui va à la DB et obtient le nombre des dossiers. Vous ne chargez rien paresseux, vous demandez au Repository un nombre, qu'il sait traduire directement en SQL.