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 个查询。是否可以通过一两个查询来做到这一点?

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 回答