2

ASP.NET MVC でブックマーク システムを開発しており、NHibernate を使用してデータベースにクエリを実行しています。

私は多対多の関係を持っています:

  • ブックマークには多くのタグを付けることができます
  • タグは多くのブックマークを持つことができます

モデル:

public class Bookmark
{
    public virtual string Title { get; set; }
    public virtual string Link { get; set; }
    public virtual User User { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public virtual string Title { get; set; }
    public virtual string Description { get; set; }
    public virtual User User { get; set; }
    public virtual ICollection<Bookmark> Bookmarks { get; set; }
}

タグを取得し、そのブックマークをループし、ブックマークごとにそのタグをループしたいと考えています。これを行うために、私はこれを使用しました:

public Tag GetTagByTitle(string username, string title)
{
    ICriteria criteriaQuery = SessionFactory.GetCurrentSession()
        .CreateCriteria(typeof(Tag))
        .SetFetchMode("Bookmarks", FetchMode.Eager)
        .CreateAlias("User", "User")
        .Add(Restrictions.Eq("Title", title))
        .Add(Restrictions.Eq("User.Username", username));

    IList<Tag> tags = criteriaQuery.List<Tag>();
    Tag tag = tags.FirstOrDefault();

    return tag;
}

これにより、ブックマーク付きのタグが作成されます。ただし、ブックマークごとに別のクエリを自動的に実行してタグを取得しています (遅延読み込み?)。したがって、10 個のブックマークがある場合、1 + 10 個のクエリが取得されます。1 つまたは 2 つのクエリでこれを行うことは可能ですか?

NHibernate Profiler の例 (3 つのブックマーク):

NHibernate Profiler を使用した例 (3 ブックマーク)

4

1 に答える 1

2

を使用CreateAliasしてブックマークを熱心にフェッチすることができます。また、別のレイヤーをより深く掘り下げて、タグをフェッチする方法を指定することもできます。

ICriteria criteriaQuery = SessionFactory.GetCurrentSession()
    .CreateCriteria(typeof(Tag))
    .CreateAlias("Bookmarks", "b", JoinType.LeftOuterJoin)
    .CreateAlias("b.Tags", "bt", JoinType.LeftOuterJoin)
    .CreateAlias("User", "User")
    .Add(Restrictions.Eq("Title", title))
    .Add(Restrictions.Eq("User.Username", username))
    .SetResultTransformer(Transformers.DistinctRootEntity);

編集:クエリを修正しました。 申し訳ありません。どうやらSetFetchMode、クエリのルートエンティティから直接離れた関係に対してのみ機能します。に置き換えるとCreateAlias問題が解決します。

これらすべてのコレクションへの左外部結合では、エンティティを少し変更し、マッピングを更新して、重複したエントリがコレクションに表示されないようにする必要があります。の代わりに名前空間からICollection<T>使用ISet<T>Iesi.Collections.Generic、マッピングを変更しての<set/>代わりに使用します<bag/>

于 2013-08-28T03:16:15.793 に答える