NHibernate在子集合上使用count对多对多的连接

时间:2013-08-29 22:05:40

标签: nhibernate fluent-nhibernate

我正在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 IList<TagWithBookmarkCount> GetTagsWithBookmarkCount(string username)
{
    ICriteria criteriaQuery = SessionFactory.GetCurrentSession()
            .CreateCriteria(typeof(Tag))
            .CreateAlias("User", "u")
            .CreateAlias("Bookmarks", "b")
            .SetProjection (Projections.ProjectionList()
            .Add (Projections.GroupProperty("Title"), "Title")
            .Add (Projections.GroupProperty("Description"), "Description")
            .Add (Projections.Count("Bookmarks"), "BookmarkCount"))
            .Add(Restrictions.Eq("u.Username", username));

    criteriaQuery.SetResultTransformer(Transformers.AliasToBean (typeof(TagWithBookmarkCount)));

    IList<TagWithBookmarkCount> tags = criteriaQuery.List<TagWithBookmarkCount>();

    return tags;
}

这会产生以下查询:

SELECT this_.Title       as y0_,
   this_.Description as y1_,
   count(this_.Id)   as y2_
FROM   Tags this_
   inner join TagsBookmarks bookmarks4_
     on this_.Id = bookmarks4_.TagId
   inner join Bookmarks b2_
     on bookmarks4_.BookmarkId = b2_.Id
   inner join Users u1_
     on this_.UserId = u1_.Id
WHERE  u1_.Username = 'Mr.nuub' /* @p0 */
GROUP  BY this_.Title,
      this_.Description

书签上的内部联接不是必需的。我在Bookmark和Tag上使用与HasManyToMany的Fluent映射。我不认为映射联结表是最佳做法。如果不映射联结表,我可以避免此连接吗?或者我不应该担心吗?

1 个答案:

答案 0 :(得分:0)

在您的情况下,Bookmarks的内部联接是不必要的。

然而,NHibernate做出这个假设是不对的。 NHibernate不知道从TagsBookmarks.BookmarkIdBookmarks存在外键约束。据他所知,这一列可以链接到一组选择的表中。

幸运的是,您的数据库知道存在外键约束,并且应该优先于查询优化此连接。你在使用SQL Server吗?尝试手动键入两个查询,一个使用内部联接到书签,另一个没有内部联接。查看执行计划,您将看到它们完全相同。

因此,你的后一个结论是正确的 - 你可以高兴地不用担心它。

<小时/> 顺便说一句,它应该是LEFT OUTER加入TagsBookmarks。否则,您的结果将省略没有书签的标签。

        .CreateAlias("Bookmarks", "b", JoinType.LeftOuterJoin)