为什么NHibernate正在进行额外的数据库调用?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么NHibernate正在进行额外的数据库调用?相关的知识,希望对你有一定的参考价值。
这是我的班级:
电影
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,流派和movies_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已经拥有了所有数据。为什么要进行这两个额外的通话?
这是因为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">
更新1:
这是违反NHibernate文档的。请参阅this链接。
从以上链接复制以下内容: -
相反,我们保留默认行为,并使用
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选择问题的一种完全不同的方法是使用二级缓存。
以上是关于为什么NHibernate正在进行额外的数据库调用?的主要内容,如果未能解决你的问题,请参考以下文章