为什么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次调用时:

  1. 在桌上电影加入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;
  2. 在桌上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;
  3. 在表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如何自动生成查询。看看你的HasManyToManyLazyLoad配置。

NH首先生成查询以从任何相关表中获取没有数据的所有movies(只有连接存在)。然后它在依赖表上为WHERE生成Primary Key子句的新查询。

然后,它使用POCOsEntities映射来自多个查询的输出。

如果你想避免这种情况并要求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正在进行额外的数据库调用?的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate,简单的问题,额外的关联

NHibernate 处理来自 sp 调用的多个结果集

Fluent Nhibernate将集合映射到通用实体

流畅的 Nhibernate 和 hbms

使用 NHibernate 作为带有输入参数的命名查询调用存储过程

NHibernate:错误脱水属性 - 这到底是什么?