我正在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映射。我不认为映射联结表是最佳做法。如果不映射联结表,我可以避免此连接吗?或者我不应该担心吗?
答案 0 :(得分:0)
在您的情况下,Bookmarks
的内部联接是不必要的。
然而,NHibernate做出这个假设是不对的。 NHibernate不知道从TagsBookmarks.BookmarkId
到Bookmarks
存在外键约束。据他所知,这一列可以链接到一组选择的表中。
幸运的是,您的数据库知道存在外键约束,并且应该优先于查询优化此连接。你在使用SQL Server吗?尝试手动键入两个查询,一个使用内部联接到书签,另一个没有内部联接。查看执行计划,您将看到它们完全相同。
因此,你的后一个结论是正确的 - 你可以高兴地不用担心它。
<小时/> 顺便说一句,它应该是
LEFT OUTER
加入TagsBookmarks
。否则,您的结果将省略没有书签的标签。
.CreateAlias("Bookmarks", "b", JoinType.LeftOuterJoin)