HIbernate загружает подклассы вместе с классами - PullRequest
8 голосов
/ 05 августа 2010

Я использую Hibernate для подключения к моей базе данных.У меня есть структура наследования в моем приложении. Проблема в том, что, когда я делаю запрос типа «from Animal», он выполняет левое внешнее соединение для класса Animal, его подклассов и всех ассоциаций для Animal и его подклассов.Как избежать этой ситуации. Я хочу загружать данные только тогда, когда я указываю их через режим выборки в моем запросе критериев?

Ответы [ 4 ]

17 голосов
/ 05 августа 2010

Да, Hibernate поддерживает полиморфные запросы.Из документации:

14,8.Полиморфные запросы

Запрос типа:

from Cat as cat

возвращает экземпляры не только Cat, но и подклассов, таких как DomesticCat.Запросы Hibernate могут называть любой класс Java или интерфейс в предложении from.Запрос вернет экземпляры всех постоянных классов, которые расширяют этот класс или реализуют интерфейс.Следующий запрос вернет все постоянные объекты:

from java.lang.Object o

Интерфейс Named может быть реализован различными постоянными классами:

from Named n, Named m where n.name = m.name

Эти два последних запроса потребуют более одного SQLSELECT.Это означает, что предложение order by некорректно упорядочивает весь набор результатов.Это также означает, что вы не можете вызывать эти запросы, используя Query.scroll().

Это поведение по умолчанию (называемое неявное полиморфизм), и Hibernate поддерживает оба неявное и явный полиморфизм:

Неявный полиморфизм означает, что экземпляры класса будут возвращены запросом, который называет любой суперкласс или реализованный интерфейс или класс, и чтоэкземпляры любого подкласса класса будут возвращены запросом, который называет сам класс. Явный полиморфизм означает, что экземпляры класса будут возвращаться только запросами, которые явно называют этот класс.Запросы, в которых указан класс, будут возвращать только экземпляры подклассов, отображенные в этом объявлении <class> как <subclass> или <joined-subclass>.Для большинства целей подходит значение по умолчанию polymorphism="implicit".Явный полиморфизм полезен, когда два разных класса сопоставлены с одной и той же таблицей. Это позволяет использовать «легкий» класс, который содержит подмножество столбцов таблицы.

Это можно настроить на уровне класса.Используйте polymorphism="explicit", если вы используете xml-сопоставления, см. 5.1.3 Class .Используйте аннотацию @Entity Hibernate, если вы используете аннотации, см. 2.4.1.Entity .Ниже приведен пример:

@javax.persistence.Entity
@org.hibernate.annotations.Entity(polymorphism = PolymorphismType.EXPLICIT)
@Inheritance(strategy = InheritanceType.JOINED)
public class Foo {
    ...
}
3 голосов
/ 05 августа 2010

Предположим, у вас есть структура класса следующим образом:

class Animal { }

class Dog : Animal { }

class Cat : Animal { }

, затем, когда вы выберете все Animal с, вы ожидаете также загрузить все Dog с и Cat с.Ведь они Animal с.

Другая история - это ассоциации.Вы можете создавать свои отображения так, чтобы ассоциации загружались лениво, а не рвались.

0 голосов
/ 19 сентября 2015

Чтобы избежать нескольких объединений во время выборки иерархии классов, вы можете применить стратегию отображения иерархии SINGLE_TABLE, а затем определить вторичные таблицы на подклассах с помощью стратегии выборки SELECT.Однако это превращает вашу модель «тяжелого соединения» в модель «N + 1 выбор».Пример:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = Super.DISCRIMINATOR_COLUMN, discriminatorType = DiscriminatorType .STRING, length = 255)
public class Super {

    public static final String DISCRIMINATOR_COLUMN = "classname";

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected long id;

    @Column(updatable = false, insertable = false)
    protected String classname;

    protected String superProp = "superProp";

    public long getId() {
        return id;
    }

    public String getClassname() {
        return classname;
    }

    public String getSuperProp() {
        return superProp;
    }

    public void setSuperProp(String superProp) {
        this.superProp = superProp;
    }

}

@Entity
@SecondaryTable(name = SubA.TABLE)
@Table(appliesTo = SubA.TABLE, fetch = FetchMode.SELECT)
public class SubA extends Super {

    public static final String TABLE = "SUBA";

    @Column(table = TABLE)
    protected String subAProp = "subAProp";

    public String getSubAProp() {
        return subAProp;
    }

    public void setSubAProp(String subAProp) {
        this.subAProp = subAProp;
    }

}

@Entity
@SecondaryTable(name = SubB.TABLE)
@Table(appliesTo = SubB.TABLE, fetch = FetchMode.SELECT)
public class SubB extends Super {

    public static final String TABLE = "SUBB";

    @Column(table = TABLE)
    protected String subBProp = "subBProp";

    public String getSubBProp() {
        return subBProp;
    }

    public void setSubBProp(String subBProp) {
        this.subBProp = subBProp;
    }

}

И что делает SQL для from Super HQL-запроса:

select [...] from SUPER super0_
select super_1_.subaprop as subaprop1_83_ from SUBA super_1_ where super_1_.id=1
select super_2_.subbprop as subbprop1_84_ from SUBB super_2_ where super_2_.id=2

Подробнее об этом подходе и общих советах по производительности в спящем режиме вы можете прочитать в myстатья .

0 голосов
/ 05 августа 2010

По сути, это шаблон проектирования наследования ORM по умолчанию, используемый Hibernate, называемый наследованием классов (все классы сопоставлены с одной таблицей), если вы хотите изменить это, вы можете google:
- иерархия одного класса или таблица для класса(это сопоставит каждый класс отдельной таблице в БД)
- конкретная иерархия классов (это сопоставит только конкретные реализации с таблицей).

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