Как лениво загрузить композицию "один к одному" через hql

StackOverflow https://stackoverflow.com/questions/965059

Вопрос

Если у объекта 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#PropertyB, выбирающего отложенную загрузку).

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

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

Спасибо, Франц

Это было полезно?

Решение

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

Что я сделал, так это создал, превратив поле EntityA#PropertyB в набор с именем 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 и указал доступ к 'field'.

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

Другие советы

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


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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top