2

これが私のドメインです:

public class ForumTheme
{
    public virtual String Name { get;set; }
}

public class ForumTopic
{
    public virtual IList<ForumTheme> Themes { get;set; }
}

public class ForumMessage
{
    public virtual IList<ForumTopic> Topics { get;set; }

    public virtual DateTime DatePosted { get; set; }
}

私が取得したいものは次のとおりです。

各ForumThemeの最新のForumMessageのトップ5を含むForumThemesのリスト

NHibernateでそれを行うことは可能ですか?

アップデート

別の可能なシナリオがあります。

ドメイン

ドメインは、典型的な階層的なブログ/ニュースサイトを記述します。

public class Channel
{
    public virtual Int32 Id { get; set; }
    public virtual String Name { get; set; }

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

public class Category
{
    public virtual IList<Article> Articles { get; set; }
}

public class Article
{
    public virtual String Name { get; set; }
    public virtual DateTime PublishDate { get; set; }
    public virtual Boolean IsActive { get; set; }
}

したがって、1つのチャネルには多くのカテゴリがあり、1つのカテゴリには多くの記事があります。

私がここでやりたいのは、各チャンネルのトップNの記事を取得することです(それらが異なるカテゴリーから来ているという事実を無視します)。記事は私のポータルのランディングページに表示されます。

アプリケーションでは、実際のデータベースデータのサブセットのみを保持するViewModelsを使用します。これが私の複合ViewModelです

DTO

public class ChannelDto
{
    public Int32 Id { get; set; }

    public String Name { get; set; }

    public List<ArticleDto> Articles { get; set; }

    public class ArticleDto
    {
        public String Name { get; set; }
    }
}

チャネルを取得するためのクエリは非常に簡単です(アクティブな記事が含まれているチャネルのみを表示します)。

Category categoryAlias = null;
Article articleAlias = null;
ChannelDto.ArticleDto articleDtoAlias = null;

List<ChannelDto> channels = _session.QueryOver<Channel>()
                                    .Inner.JoinAlias(x => x.Categories, () => categoryAlias)
                                    .Inner.JoinAlias(x => categoryAlias.Articles, () => articleAlias)
                                    .Where(x => articleAlias.IsActive)
                                    .SelectList(list => list
                                        .Select(x => x.Id)
                                        .Select(x => x.Name)
                                    )
                                    .List<Object[]>
                                    .Select(x => new ChannelDto
                                    {
                                        Id = (Int32) x[0],
                                        Name = (String) x[1]
                                    })
                                    .ToList();

上記のクエリは、アクティブな記事があるチャンネルのリストを表示します。今、私は記事自体を取得します:

foreach(var channel in channels)
{
    channel.Articles = _session.QueryOver<Channel>()
                               .Inner.JoinAlias(x => x.Categories, () => categoryAlias)
                               .Inner.JoinAlias(x => categoryAlias.Articles, () => articleAlias)
                               .Where(x => x.Id == channel.Id)
                               .OrderBy(x => articleAlias.PublishDate).Desc
                               .SelectList(list => list
                                   .Select(x => articleAlias.Name).WithAlias(() => articleDtoAlias.Name)
                               )
                               .Take(5)
                               .List<Object[]>
                               .Select(x => new ChannelDto.ArticleDto
                               {
                                   Name = (String) x[0]
                               })
                               .ToList();
}

ただし、上記の2つのクエリには、SELECT+1の問題が発生します。先物を使うと、より少ない往復でそれができると思います。私はまだNHibernateにあまり詳しくありません。1回のラウンドトリップですべてを取得してDTOをハイドレイトすることは可能ですか?QueryOverでROW_NUMBER()OVER(PARTITION BY ....)のようなものを使用しますか?HQLや生のSQLは使いたくありません。

4

1 に答える 1

3

2回のラウンドトリップを使用

var themes = session.Query<ForumTheme>().Select(t => new ThemeDto(t.Name)).List();

var topMessages = new List<IEnumerable<string>>(themse.Count);

foreach(var theme in themes)
{
    var query = from message in session.Query<ForumMessage>()
                from topic in message.Topics
                from t in topic.Themes
                where t.Name == theme.Name
                orderby message.DatePosted desc
                select message;
    topMessages.Add(query.Take(5).ToFuture());
}

for(int i = 0;i < topMessages.Count; i++)
{
    themes.TopMessages = topMessages[i].ToList();
}

return themes;

2番目のシナリオの場合

foreach(var channel in channels)
{
    channel.Articles = _session
        .QueryOver<Channel>()
        .Inner.JoinAlias(x => x.Categories, () => categoryAlias)
        .Inner.JoinAlias(x => categoryAlias.Articles, () => articleAlias)
        .Where(x => x.Id == channel.Id)
        .OrderBy(x => articleAlias.PublishDate).Desc
        .SelectList(list => list
            .Select(x => articleAlias.Name).WithAlias(() => articleDtoAlias.Name)
        )
        .TransformUsing(Transformers.AliasToBean<ChannelDto.ArticleDto>());
}

// execute all subqueries at once through iterating one
channels[0].Articles.Any();
于 2012-10-11T08:54:38.553 に答える