3

У меня есть события, которые могут иметь много EventTypes. Я пытаюсь запросить базу данных с помощью сопоставлений NHibernate, которые я определил. Проблема в том, что при определении критериев для дочерних объектов NHibernate делает повторные вызовы в базе данных, а не делает один вызов для всех необходимых ему данных. Это приводит к чрезвычайно медленному поиску.NHibernate критерии many-to-many, создающие множественные вызовы базы данных

таблицы базы данных следующим образом:

класс
Event 
-EventID 

EventType 
-EventTypeID 

EventEventTypeID 
-EventEventTypeID 
-EventID 
-EventTypeID 

Событие выглядит следующим образом:

Id as Integer 
Types as IList(Of EventType) 

Класс 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 для Тип свойства Event.

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, как это (где QuickSearch мой пользовательский ввод):

.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] 

(где @ р0 каждый из 50 главных событий, которые возвращаются при поиске)

Я чувствую, что для этого нужно только первый звонок.

Является ли это отношением «многие ко многим», что означает, что NHibernate нужны эти дополнительные вызовы? Есть что-то в моем картографировании, которое я пропустил?

Возможно, важно, чтобы я использовал ту же технику для свойств String события и отношения «один ко многим» от события, и для поиска требуется только один вызов. Проблема, похоже, существует только со многими отношениями.

Извинения за длинный вопрос, и спасибо за то, что вы достигли этого. Я прочитал много вопросов по подобной теме, но не смог найти решение проблем повторных запросов базы данных для отношений «многие ко многим».

ответ

3

Что вы описываете, является проблемой nHibernate n+1 (в основном количество выполненных запросов прямо пропорционально размеру набора результатов), что может быть трудно разрешено в зависимости от того, насколько сложным является ваш запрос.

Хотя не очевидное решение, что работает для меня в прошлом, чтобы изменить тип присоединиться к левому внешнему соединению, как показано ниже:

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

Wow - это работает. Только один звонок в базу данных. Мне хотелось бы узнать, что такое логика. Большое спасибо за вашу помощь. – phillyd