我在 ASP.NET MVC 中创建一个网站并使用 NHibernate 作为 ORM。我的数据库中有以下表格:
- 书签
- 标签书签(连接表)
- 标签
映射:
public BookmarkMap()
{
Table("Bookmarks");
Id(x => x.Id).Column("Id").GeneratedBy.Identity();
Map(x => x.Title);
Map(x => x.Link);
Map(x => x.DateCreated);
Map(x => x.DateModified);
References(x => x.User, "UserId");
HasManyToMany(x => x.Tags).AsSet().Cascade.None().Table("TagsBookmarks").ParentKeyColumn("BookmarkId")
.ChildKeyColumn("TagId");
}
public TagMap()
{
Table("Tags");
Id(x => x.Id).Column("Id").GeneratedBy.Identity();
Map(x => x.Title);
Map(x => x.Description);
Map(x => x.DateCreated);
Map(x => x.DateModified);
References(x => x.User, "UserId");
HasManyToMany(x => x.Bookmarks).AsSet().Cascade.None().Inverse().Table("TagsBookmarks").ParentKeyColumn("TagId")
.ChildKeyColumn("BookmarkId");
}
我需要 Bookmarks 和 Tags 表中的数据。更具体地说:我需要 20 个带有相关标签的书签。我要做的第一件事是从 Bookmarks 表中选择 20 个书签 ID。我这样做是因为分页不适用于我在第二个查询中获得的笛卡尔积。
第一个查询:
IEnumerable<int> bookmarkIds = (from b in SessionFactory.GetCurrentSession().Query<Bookmark>()
where b.User.Username == username
orderby b.DateCreated descending
select b.Id).Skip((page - 1) * pageSize).Take(pageSize).ToList<int>();
之后,我为这些 id 选择书签。
第二个查询:
IEnumerable<Bookmark> bookmarks = (from b in SessionFactory.GetCurrentSession().Query<Bookmark>().Fetch(t => t.Tags)
where b.User.Username == username && bookmarkIds.Contains(b.Id)
orderby b.DateCreated descending
select b);
我使用 fetch 的原因是因为我想避免 N+1 查询。这可行,但会产生笛卡尔积。我在一些帖子中读到你应该避免笛卡尔积,但我真的不知道如何在我的情况下做到这一点。
我还阅读了有关为 N+1 查询设置批量大小的内容。这真的比这个单一的查询快吗?
用户最多可以向书签添加 5 个标签。我每页选择 20 个书签,因此第二个查询的最坏情况是:5 * 20 = 100 行。
当书签和标签表中有大量数据时,这会影响性能吗?我应该这样做吗?