开发者

How do I do a OfType<>().Count() on a heterogenous collection in NHibernate?

开发者 https://www.devze.com 2023-01-29 03:01 出处:网络
I have an entity that looks like this: public class Album { public virtual string Name { get; set; } public virtual IEnumerable<Media> { get; set; }

I have an entity that looks like this:

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>(); }
    }
}

Where Media is the abstract base class and Picture, Video, and Audio are subtypes of Media, so the IEnumerable<Media> collection is heterogenous.

I have a DTO for Album that looks like this:

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

Where each count is being populated by doing <collection>.Count();. Although this code works fine and I get the count for each media type, the generated SQL is less than ideal:

SELECT * FROM Media WHERE media.Album_id = 1
SELECT * FROM Media WHER开发者_C百科E media.Album_id = 2
SELECT * FROM Media where media.Album_id = 3

In other words, it's grabbing all the Media first from the database, and then performing the OfType<T>.Count() afterwards in memory. Problem is, if I'm doing this over all the Albums, it will select all the Media from the database, which potentially could be thousands of records. Preferably, I'd like to see something like this (I'm using table-per-hierarchy 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'

Does anyone know how I can configure NHibernate to do this? Or will I have to modify my Album entity in order to get the correct behavior?


First off, your code won't compile; you're missing the property name of the IEnumerable<Media> (I assume it's Media), and also of the filters.

Second, you have to understand a little about what's going on. From this behavior, I'm pretty sure you've mapped your Album with a HasMany relationship to Media. NH lazy-loads by default, so when you first retrieve the Album from the DB, Media is given a reference to an NHibernate object called a PersistentBag. This is simply a placeholder that looks like an IEnumerable, and holds the logic to populate the real list when it is actually needed. All it can do is pull the records as mapped in the HBM when its GetEnumerator() method is called (and that happens in virtually every Linq method). So, when you call OfType, you're not working with an NHibernate IQueryable anymore, which can build a SQL statement that does exactly what you want. Instead, you're asking for each element in the list you think you already have, and NHibernate complies.

You have some options if all you want is the Count. The easiest, if possible, is simply to go back to the Session and ask for a whole new query on Album:

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

This will directly build a statement that goes to the DB and gets the count of the records. You're not lazy-loading anything, you're asking the Repository for a count, which it knows how to directly translate to SQL.

0

精彩评论

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

关注公众号