Я начну с того, что уже тщательно изучил переполнение стека, nhusers и документацию для возможного решения моей проблемы.
Мне нужно иметь возможность запрашивать только таблицу базовых классов в частях моего мульти / будущего запроса при активной загрузке ассоциаций (хотя из проведенного мною исследования я не думаю, что это возможно)
Я начал отображать существующую схему, используя свободный nhibernate в качестве подтверждения концепции. Я отобразил иерархию наследования, используя таблицу для каждого подкласса (все сопоставления работают отлично, поэтому я не буду вставлять их все здесь). Иерархия имеет около 15 подклассов, а базовый класс имеет некоторые дополнительные ассоциации. Э.Г.
Base
Dictionary<string, Attribute> Attributes
List<EntityChange> Changes
Мне нужно срочно загрузить обе коллекции, так как в данном сценарии они требуются для последующей обработки, и их ленивая загрузка вызывает проблемы с производительностью. Я с нетерпением загружаю их по мульти / будущему запросу:
var baseQuery = session.CreateCriteria<Base>("b")
.CreateCriteria("Nested", JoinType.LeftOuterJoin)
.CreateCriteria("Nested2", JoinType.LeftOuterJoin)
.CreateCriteria("Nested2.AdditionalNested", JoinType.LeftOuterJoin);
var logsQuery = session.CreateCriteria<Base>("b").CreateAlias("Changes", "c", JoinType.LeftOuterJoin,
Expression.And(Expression.Ge("c.EntryDate", changesStartDate), Expression.Le("c.EntryDate", changesEndDate)))
.AddOrder(Order.Desc("c.EntryDate"));
var attributesQuery = session.CreateCriteria<Base>("t").SetFetchMode("Attributes", FetchMode.Join);
logsQuery.Future<Base>();
attributesQuery.Future<Base>();
var results = baseQuery.Future<Base>().ToList();
Запросы выполняются и возвращают правильные результаты. Но просто загружать ассоциации таким образом означает, что запросы атрибутов и изменений должны выполнять полиморфную выборку (добавление около 15 левых внешних объединений на запрос, которые не требуются). Я знаю, что это требуется для полиморфных запросов, но базовый запрос вернет иерархию, которую я желаю. Другие части мультизапроса, которые создают полиморфный запрос, являются избыточными.
Я еще не отобразил всю иерархию, поэтому будут выполняться дополнительные ненужные объединения, а также есть другие ассоциации, которые могут быть загружены заранее. Эти два, объединенные без увеличения объема, приведут к проблемам с производительностью. Производительность этого запроса в настоящее время составляет около 6 секунд (что, по общему признанию, лучше, чем 20, которые он в настоящее время занимает), но, немного возившись с запросом и выбрав дополнительные объединения, я могу уменьшить его примерно до 2 секунд (это общий запрос, поэтому получение его как можно ниже, полезно не только для меня. Он также будет выполняться с нескольких распределенных компьютеров, поэтому я бы не стал обсуждать кэширование / кэширование 2-го уровня).
Я пытался
- с использованием модификатора класса в запросе 'class = base'. Я изначально делал это вслепую, но считаю, что это для ценностей дискриминатора. Даже если это для оператора case в SQL, это не помешает дополнительным соединениям.
- Делать все за один запрос. Это медленнее, чем разделение, как указано выше, и дает декартово произведение
- Использование 'Polymorphism.Explicit ();' в беглых отображениях. Это не имеет никакого эффекта, так как я использую ClassMap с SubclassMaps, поэтому он игнорируется. Я попытался изменить все карты на ClassMaps и использовать Join, но это не дало желаемого поведения.
- Попытка обмануть nhibernate, чтобы объединить таблицу базовых классов в себя для загрузки ассоциаций (в основном, загрузить более конкретный тип для предотвращения полиморфного запроса) - создать производный класс BaseOnlyLoading, который использует ту же таблицу и первичный ключ, что и базовый. учебный класс. Это было очевидно взломом, но я просто пытался понять, что возможно. NHibernate не позволяет классу и подклассу использовать одну и ту же таблицу.
- Определите BaseOnlyLoadingMap как карту классов с теми же ассоциациями, что и BaseMap, с присоединением к Base. Это вселяло надежду, поскольку коллекции сопоставлений разрешаются в контексте на основе полного имени типа.
- Используйте перехватчик, который изменяет SQL перед его выполнением. Я бы не стал использовать это в производстве, а просто попробовал из интереса. Я передал перехватчик в локальную сессию. Это вызвало проблемы, и я не продолжил.
- Оператор запроса HQL 'Type', как объяснено здесь , хотя я не уверен, что он реализован в версии .NET и может вести себя аналогично 1.
Есть комментарий к ответу с самым высоким рейтингом ( Как выполнить неполиморфный HQL-запрос в Hibernate? ), который предлагает переопределить IsExplicitPolymorphism на персистенте. Я быстро посмотрел, и из того, что я помню, персистер был либо глобальным для каждой сущности, либо создан в SessionImpl из статической фабрики, которая помешала бы сделать это. Даже если бы это было возможно, я не уверен, какие побочные эффекты это будет иметь.
Я пытался использовать SQL для загрузки всего, но даже если я использую хранимый процесс, я не уверен, как nhibernate соберет график обратно. Может быть, я мог бы указать все сущности и псевдонимы?
Было бы неплохо указать явный для каждого запроса. Есть предложения?
Заранее спасибо.