这是我的班级:
电影
List<Person> Actors
List<Genre> Genres
MovieMap
HasManyToMany(x => x.Genres)
.Table("movies_genres")
.ParentKeyColumn("movie_id")
.ChildKeyColumn("genre_id")
.Cascade.SaveUpdate().LazyLoad();
HasManyToMany(x => x.Actors)
Table("movies_actors")
.ParentKeyColumn("movie_id")
.ChildKeyColumn("person_id")
.Cascade.SaveUpdate().LazyLoad();
存储库方法
public Movie get_movie_by_id(int id)
{
var movie = _session.CreateCriteria(typeof(Movie))
.CreateAlias("Genres", "mg")
.SetFetchMode("Genres", FetchMode.Eager)
.CreateAlias("Actors", "ma")
.SetFetchMode("Actors", FetchMode.Eager)
.Add(Restrictions.Eq("Id", id))
.UniqueResult<Movie>();
return movie;
}
当我呼叫get_movie_by_id()
NHibernate向SQL服务器发出 3次调用时:
关于加入movies_genres,流派和movie_actors,演员的桌上电影
SELECT
(...removed it all to make it shoerter...)
FROM movies this_ inner join movies_genres genres4_ on this_.id=genres4_.movie_id inner join genre mg1_ on genres4_.genre_id=mg1_.id inner join movies_actors actors6_ on this_.id=actors6_.movie_id inner join person ma2_ on actors6_.person_id=ma2_.id left outer join person person8_ on this_.director_id=person8_.id left outer join countries country9_ on this_.country_id=country9_.id WHERE this_.id = @p0;
关于加入流派的桌子movie_genres
SELECT genres0_.movie_id as movie1_1_, genres0_.genre_id as genre2_1_, genre1_.id as id3_0_, genre1_.name as name3_0_ FROM movies_genres genres0_ left outer join genre genre1_ on genres0_.genre_id=genre1_.id WHERE genres0_.movie_id=@p0;
关于加入演员的桌子movies_actors
SELECT actors0_.movie_id as movie1_1_, actors0_.person_id as person2_1_, person1_.id as id4_0_, person1_.name as name4_0_ FROM movies_actors actors0_ left outer join person person1_ on actors0_.person_id=person1_.id WHERE actors0_.movie_id=@p0;
在第一次调用中,NHibernate已经拥有了所有数据。为什么要进行这两个额外的通话?
答案 0 :(得分:0)
这是因为NHibernate
如何自动生成查询。查看您的HasManyToMany
和LazyLoad
配置。
NH
首先生成查询以从任何相关表中获取没有数据的所有movies
(只有连接存在)。然后它在依赖表上为WHERE
生成Primary Key
子句的新查询。
然后,它会使用您的POCOs
或Entities
来映射多个查询的输出。
如果您想避免这种情况并要求NH
一次性检索数据,请尝试删除LazyLoad
。使用.hbm
文件,您可以通过<set name = "PocoName" table = "TableName" fetch = "join">
或者,您可以使用预先加载。我不确定如何使用代码配置执行此操作,但您可以尝试删除对LazyLoad
的调用。
使用.hbm文件,您可以使用以下内容强制执行急切加载: -
<class name="A" table="A" lazy="false">
这反对NHibernate文档。请参阅this链接。
从上面的链接复制以下内容: -
相反,我们保留默认行为,并为a覆盖它 特定交易,使用
left join fetch
中的HQL
。这说明 NHibernate在第一个选择中急切地获取关联,使用 外连接。在ICriteria
查询API中,您可以使用SetFetchMode(FetchMode.Join)
。如果您觉得自己希望改变抓取策略 由
Get()
或Load()
使用,只需使用ICriteria
查询即可 例如:User user = (User) session.CreateCriteria<User>() .SetFetchMode("Permissions", FetchMode.Join) .Add( Expression.Eq("Id", userId) ) .UniqueResult();
避免N + 1选择问题的一种完全不同的方法是 使用二级缓存。