I have Events, which can have many EventTypes. I'm attempting to query the database by using the NHibernate mappings I have defined. The issue is that when defining criteria on child objects, NHibernate makes repeated calls to the database, rather than making one call for all the data it needs. This leads to an extremely slow search.
The database tables are as follows:
Event
-EventID
EventType
-EventTypeID
EventEventTypeID
-EventEventTypeID
-EventID
-EventTypeID
The Event class looks like this:
Id as Integer
Types as IList(Of EventType)
The EventType class looks like this:
Id as Integer
FullTitle as String
There is no EventEventType class.
The NHibernate mappings are as follows:
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")
On the open of my form, the following function is called, which sets the FetchMode for the Types property of Event.
Public Function CreateListViewQuery(currentNHibernateSession As ISession) As NHibernate.ICriteria Implements IListViewQueryable.CreateListViewQuery
Return currentNHibernateSession.CreateCriteria(Of [Event])().SetFetchMode("Types", FetchMode.Join)
End Function
This is used to populate the listview, which happens extremely quickly, with just one call to the database for all the data:
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
However, when I add a Criterion.Expression, like this (where QuickSearch is my user input):
.CreateAlias("Types", "t", NHibernate.SqlCommand.JoinType.InnerJoin)
.Add(NHibernate.Criterion.Expression.Like("t.FullTitle", QuickSearch))
I get 1 call which looks like this:
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
And 50 more calls which look like this (50 as I have selected TOP 50):
SELECT
types0_.*
FROM
event.EventEventType types0_
left outer join event.EventType eventtype1_ on types0_.EventTypeID=eventtype1_.EventTypeID
WHERE types0_.EventID=@p0
(where @p0 is each of the TOP 50 Events which are returned by the search)
I feel like only the first call should be necessary for this.
Is it the nature of a many-to-many relationship which means NHibernate needs these additional calls? Is there something in my mapping which I've missed?
Perhaps importantly, I have used exactly the same technique for String properties of Event, and one-to-many relationships from Event and only one call is required for the search. The problem seems to only exist with many-to-many relationships.
Apologies for the long question, and thank you for getting this far. I've read many questions on a similar topic but couldn't find any addressing the issues of repeated database calls for many-to-many relationships.