1

我正在 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

书签上的内部连接不是必需的。我在书签和标签上都使用带有 HasManyToMany 的 Fluent 映射。我不认为映射联结表是最佳实践。我可以在不映射联结表的情况下避免这种联接吗?还是我不应该担心?

4

1 回答 1

0

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

然而,NHibernate 做出这样的假设是错误的。NHibernate 不知道从TagsBookmarks.BookmarkIdto存在外键约束Bookmarks。据它所知,此列可能链接到任何一个表选择。

幸运的是,您的数据库确实知道存在外键约束,并且应该在您的查询之外优化此连接。你在使用 SQL Server 吗?尝试手动键入两个查询,一个带有内连接到书签,一个没有内连接。查看执行计划,您会发现它们是相同的。

因此,您的后一个结论是正确的-您可以很高兴地不必担心。


顺便说一句,它确实应该LEFT OUTERTagsBookmarks. 否则,您的结果将忽略具有零书签的标签。

        .CreateAlias("Bookmarks", "b", JoinType.LeftOuterJoin)
于 2013-08-30T00:35:38.733 回答