3

我有事件,它可以有很多事件类型。我试图通过使用我定义的NHibernate映射来查询数据库。问题是,在定义子对象标准时,NHibernate会重复调用数据库,而不是一次调用它所需的所有数据。这导致搜索速度极慢。NHibernate的多对多标准创建多个数据库调用

的数据库表如下:

Event 
-EventID 

EventType 
-EventTypeID 

EventEventTypeID 
-EventEventTypeID 
-EventID 
-EventTypeID 

Event类看起来是这样的:

Id as Integer 
Types as IList(Of EventType) 

的事件类型类看起来是这样的:

Id as Integer 
FullTitle as String 

没有EventEventType类。

NHibernate的映射如下:

EventMapping资料

Table("event.Event") 
Id(Function(x) x.Id).Column("EventID").GeneratedBy().Identity() 
HasManyToMany(Of EventType)(Function(x) .Types).Table("event.EventEventType").ParentKeyColumn("EventID").ChildKeyColumn("EventTypeID").Cascade.All() 

EventTypeMapping

Table("event.EventType") 
Id(Function(x) x.Id).Column("EventTypeID").GeneratedBy().Identity() 
Map(Function(x) x.FullTitle).Column("EventTypeFullTitle") 

在开我的形式,下面的函数被调用,这台FetchMode为事件的类型属性。

Public Function CreateListViewQuery(currentNHibernateSession As ISession) As NHibernate.ICriteria Implements IListViewQueryable.CreateListViewQuery 

     Return currentNHibernateSession.CreateCriteria(Of [Event])().SetFetchMode("Types", FetchMode.Join) 

End Function 

这是用来填充ListView,这非常迅速发生,只需一个电话到数据库中的所有数据:

SELECT TOP (50) 
    this_.EventID as EventID 
    , t3_.EventTypeID as EventTyp1_15_0_ 
    , t3_.EventTypeFullTitle as EventTyp2_15_0_ 
FROM event.Event this_ 
    inner join event.EventEventType types5_ on this_.EventID=types5_.EventID 
    inner join event.EventType t3_ on types5_.EventTypeID=t3_.EventTypeID 

然而,当我加入Criterion.Expression,像这个(其中快速搜索我的用户输入):

.CreateAlias("Types", "t", NHibernate.SqlCommand.JoinType.InnerJoin) 
.Add(NHibernate.Criterion.Expression.Like("t.FullTitle", QuickSearch)) 

我得到1个调用,它看起来是这样的:

SELECT TOP 50 
    this_.EventID as EventID12_6_ 
    , types8_.EventID as EventID 
    , t3_.EventTypeID as EventTyp2_ 
    , t3_.EventTypeFullTitle as EventTyp2_15_0_ 
FROM 
    event.Event this_ 
     inner join event.EventEventType types8_ on this_.EventID=types8_.EventID 
     inner join event.EventType t3_ on types8_.EventTypeID=t3_.EventTypeID 
WHERE t3_.EventTypeFullTitle like @p1 

和50多个电话,看起来像这样(50,我选择了TOP 50):

SELECT 
    types0_.* 
FROM 
    event.EventEventType types0_ 
     left outer join event.EventType eventtype1_ on types0_.EventTypeID=eventtype1_.EventTypeID 
WHERE [email protected] 

(其中@ P0为每个被搜索返回的TOP 50事件)

我觉得只有第一个电话应该是必要的。

它是一个多对多关系的性质,这意味着NHibernate需要这些额外的调用?我的地图中有什么我错过了?

也许重要的是,我使用了完全相同的技术来处理事件的字符串属性,以及来自事件的一对多关系,并且只需要一次调用就可以进行搜索。这个问题似乎只存在于多对多的关系中。

对于长期问题的道歉,并感谢您获得这个目标。我已阅读了许多有关类似主题的问题,但找不到解决多次数据库调用多对多关系的问题。

回答

3

您所描述的是nHibernate n+1问题(基本上执行的查询数量与结果集大小成正比),根据查询的复杂程度可能难以解决。

虽然不是一个显而易见的解决方案是什么为我在过去的工作是要改变连接类型左外连接如下:

.CreateAlias("Types", "t", NHibernate.SqlCommand.JoinType.LeftOuterJoin) 
+0

哇 - 它的工作原理。现在只有一个调用数据库。我很想知道这背后的逻辑。非常感谢您的帮助。 – phillyd