Как мне сделать OfType <> (). Count () для гетерогенной коллекции в NHibernate? - PullRequest
1 голос
/ 07 декабря 2010

У меня есть объект, который выглядит следующим образом:

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 - абстрактный базовый класс, а Picture, Video и Audio - это подтипы Media, поэтому коллекция IEnumerable<Media> является гетерогенной.

У меня есть DTO для Album, которое выглядит так:

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

Где каждый счет заполняется с помощью <collection>.Count();. Хотя этот код работает нормально, и я получаю счетчик для каждого типа носителя, сгенерированный SQL не идеален:

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

Другими словами, он сначала захватывает все Media из базы данных, а затем выполняет OfType<T>.Count() в памяти. Проблема в том, что если я делаю это для всех Albums, он выберет все Media из базы данных, которые потенциально могут быть тысячами записей. Предпочтительно, я хотел бы видеть что-то вроде этого (я использую отображение таблицы на иерархию):

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'

Кто-нибудь знает, как я могу настроить NHibernate для этого? Или мне придется изменить свою сущность Album, чтобы получить правильное поведение?

1 Ответ

2 голосов
/ 08 декабря 2010

Во-первых, ваш код не будет компилироваться; вам не хватает имени свойства IEnumerable<Media> (я полагаю, что это Media), а также фильтров.

Во-вторых, вы должны немного понять, что происходит. Исходя из этого, я уверен, что вы сопоставили свой альбом с отношением HasMany к Media. По умолчанию NH выполняет отложенную загрузку, поэтому при первом получении Альбома из БД Media дается ссылка на объект NHibernate, который называется PersistentBag. Это просто заполнитель, который выглядит как IEnumerable и содержит логику для заполнения реального списка, когда он действительно необходим. Все, что он может сделать, это извлечь записи как отображенные в HBM, когда вызывается его метод GetEnumerator () (и это происходит практически в каждом методе Linq). Итак, когда вы вызываете OfType, вы больше не работаете с NHibernate IQueryable, который может создать оператор SQL, который будет выполнять именно то, что вы хотите. Вместо этого вы запрашиваете каждый элемент в списке, который, по вашему мнению, у вас уже есть, и NHibernate соответствует.

У вас есть несколько вариантов, если вам нужен только граф. Самый простой, если это возможно, просто вернуться на сессию и запросить новый запрос в альбоме:

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

Это непосредственно создаст оператор, который отправляется в БД и получает количество записей. Вы ничего не загружаете, вы запрашиваете в репозитории счетчик, который он умеет напрямую переводить в SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...