Я использую Nhibernate для своего ORM.
У меня есть класс «Control», который имеет отношение один ко многим с ControlDetail (т. Е. Элемент управления имеет много controlDetails).
В конфиге управления xml оно имеет следующий
<bag name="ControlDetails" lazy="true" access="property" order-by="SortOrder asc" cascade="all-delete-orphan"
table="ControlDetail">
<key column="ControlID"/>
<one-to-many class="ControlDetail"/>
</bag>
так, что, я полагаю, если не указано иное, лениво загружать детали управления элемента управления.
Я использую NHProf, чтобы попытаться исправить некоторые проблемы с производительностью, которые у нас возникают, и он выявил проблему Select N + 1 вокруг этих классов.
Мы используем слой DA репозитория, и я попытался выяснить, могу ли я добавить способ, чтобы с готовностью получать данные, когда это необходимо, и придумал это.
public T GetById<T>(Int32 id, List<string> fetch) where T : BaseObject
{
T retObj = null;
ISession session = EnsureCurrentSession();
{
ICriteria criteria = session.CreateCriteria(typeof (T));
criteria.SetCacheable(true);
criteria.Add(Expression.Eq("Id", id));
foreach(var toFetch in fetch)
{
criteria.SetFetchMode(toFetch, FetchMode.Eager);
}
retObj = criteria.List<T>().FirstOrDefault();
}
return retObj;
}
* Примечание: я не фанат того, как настраивается репозиторий, но это было сделано до того, как я пришел в проект, поэтому мы должны придерживаться этого шаблона на данный момент.
Я называю этот метод примерно так
public Control GetByIDWithDetail(int controlID)
{
return DataRepository.Instance.GetById<Control>(controlID, new List<string>() {"ControlDetail"});
}
Когда я отлаживаю метод GetByID и смотрю на retObj, я вижу, что список ControlDetails заполнен (хотя, как ни странно, я также заметил, что без набора setfetchmode список заполняется)
Даже с этим исправлением NHProf выявляет проблему Select N + 1 со следующей строкой
List<ControlDetail> details = control.ControlDetails.ToList();
Что именно мне не хватает и как я могу остановить это N + 1, но все же перебирать список controlDetails
РЕДАКТИРОВАТЬ: конфиги xml выглядят так (слегка отредактированы, чтобы уменьшить)
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="DomainObjects" assembly="DomainObjects">
<class name="Control" lazy="false" table="Control" optimistic-lock="version" select-before-update="true" >
<id name="Id" type="int" column="ControlID" access="property">
<generator class="native" />
</id>
<version name="Version" column="Version" />
<property name="AdministrativeControl" column="AdministrativeControl" access="property" not-null="true" />
<property name="Description" column="ControlDescription" access="property" />
<property name="Title" column="Title" access="property" />
<property name="CountOfChildControls" access="property" formula="(select count(*) from Control where Control.ParentControlID = ControlID)" />
<bag name="ControlDetails" lazy="true" access="property" order-by="SortOrder asc" cascade="all-delete-orphan"
table="ControlDetail">
<key column="ControlID" />
<one-to-many class="ControlDetail" />
</bag>
</class>
</hibernate-mapping>
и это
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="DomainObjects" assembly="DomainObjects">
<class name="ControlDetail" lazy="false" table="ControlDetail" select-before-update="true" optimistic-lock="version">
<id name="Id" type="int" column="ControlDetailID" access="property">
<generator class="native" />
</id>
<version name="Version" column="Version" />
<property name="Description" column="Description" access="property" not-null="true" />
<property name="Title" column="Title" access="property" />
<many-to-one name="Control" lazy="false" class="Control" column="ControlID" access="property"/>
</class>
</hibernate-mapping>