Как лениво загружать композицию один на один через hql - PullRequest
1 голос
/ 08 июня 2009

Если есть объект A с двунаправленным отображением один-или-ноль-к-одному с объектом B.

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

<class name="EntityA" table="TABLE_A" mutable="true" lazy="true">
    <id name="idA" type="long" column="pk_a" unsaved-value="null">
        <generator class="sequence">
            <param name="sequence">pk_a_seq</param>
        </generator>
    </id>
    <one-to-one name="propertyB" class="EntityB" property-ref="propertyA" constrained="true" outer-join="false"/>
</class>

и

<class name="EntityB" table="TABLE_B" mutable="true" lazy="true">
    <id name="idB" type="long" column="pk_b" unsaved-value="null">
        <generator class="sequence">
            <param name="sequence">pk_b_seq</param>
        </generator>
    </id>
    <many-to-one name="propertyA" class="EntityA" not-null="true" unique="true" lazy="proxy" column="fk_a"/>
</class>

Когда я делаю hql-запрос (или, точнее, именованный hql-запрос) для EntityA, hibernate охотно загружает EntityA # propertyB с отдельным оператором select.

Моя проблема в том, что если мой hql возвращает 1000 объектов EntityA (все имеют свои собственные соответствующие объекты EntityB), hibernate выполнит n + 1 запрос (1-й запрос будет для EntityA, возвращающего 1000 результатов, тогда как n запросов будет поступать свойство EntityA # выбирает отложенную загрузку).

Однако мне не нужны эти EntityA # propertyB, поэтому я вместо этого хочу их лениво загрузить (не используя hibernate, используя отдельный SQL-запрос).

Это возможно? И если это так, как мне это сделать?

Спасибо, Franz

Ответы [ 2 ]

2 голосов
/ 23 июля 2009

Я исправил эту проблему.

Что я сделал, так это создал поле EntityA # propertyB, превратив его в Set с именем EntityA # propertyBs. Но я сохранил методы доступа EntityA # getPropertyB () и EntityA # setPropertyB (EntityB propertyB).

Тела методов этих методов доступа теперь выглядят примерно так:

public EntityB getPropertyB() {
    return CollectionUtils.get(propertyBs, 0);
}

public void setPropertyBs(EntityB propertyB) {
    propertyBs= Collections.singleton(propertyB);
}

Затем в своем отображении я отобразил набор EntityA # propertyBs и указал доступ к «полю».

<set name="scheduledAdInfos" lazy="true" fetch="subselect" access="field" cascade="none" inverse="true">
    <key column="pk_a"/>
    <one-to-many class="EntityB"/>
</set>

С помощью этой настройки вы можете теперь создать ленивое сопоставление с владельцем POJO (EntityA) на принадлежащий POJO (EntityB), даже если TABLE_A принадлежит TABLE_B.

0 голосов
/ 10 июня 2009

Краткий ответ: Нет, вы не можете сделать это, по крайней мере, без изменения базы данных и отображения. В основном вам нужно обратить взаимно однозначное сопоставление и отношение внешнего ключа, чтобы работать так, как вы хотите.


Более длинный ответ: Hibernate может лениво загружать ассоциации. Это делается путем внедрения прокси-объекта, который содержит идентификатор объекта, на который есть ссылка.

В вашем случае сопоставление таково, что столбец внешнего ключа находится в TABLE_B, то есть там, где вы используете сопоставление многие-к-одному. Поэтому, если вы загрузите B, Hibernate найдет ссылку FK в столбце fk_a и может создать прокси, который содержит это значение. При обращении к прокси загружается соответствующий объект.

Что если выбрать запись из таблицы A? Hibenate создаст объект A, но чтобы иметь возможность заполнить свойство B, ему нужно будет заглянуть в TABLE_B, чтобы найти соответствующую строку с fk_a = a.id. У Hibernate нет другого способа узнать, какую запись загружать во время отложенной загрузки.

На самом деле, это было бы улучшением для Hibernate, поскольку он также должен иметь возможность загружать другие уникальные ключи во время отложенной загрузки, но текущая реализация этого не позволяет, возможно, вы можете поднять проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...