Полиморфный «get» с использованием гибернации, многие к одному, InheritanceType .Присоединился

#hibernate #inheritance #polymorphism

#гибернация #наследование #полиморфизм

Вопрос:

У меня есть что-то вроде этого..

Класс автомобиля, который имеет одно место из многих мест. Seat имеет подкласс LeatherSeat .

 public class Car {
  private Seat seat;
  ...
  @ManyToOne(fetch = FetchType.LAZY)
  public Seat getSeat() {
    return seat;
  }
  ...
}

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Seat {
  private String id;
  private String color;
} 

@Entity
public class LeatherSeat extends Seat {
    private String leatherType;
}
  

Когда я создаю свой автомобиль и превращаю сиденье моего автомобиля в кожаное сиденье, все правильно сохраняется в БД. Когда я хочу затем получить свою машину (используя критерии или список запросов) и я читаю getSeat(), сиденье всегда просто сиденье, а не кожаное сиденье. Я не могу привести (исключение) и, по-видимому, должен вручную получить LeatherSeat по идентификатору.

Является ли это ограничением использования ОБЪЕДИНЕННОГО типа наследования или я что-то упускаю. Как мне получить Seat в качестве кожаного кресла?

Ответ №1:

В ЛЕНИВОМ случае seat будет «прокси», экземпляр которого создается при создании экземпляра Car. В это время Hibernate не знает, будет ли сиденье кожаным или нет.

Когда вы просматриваете свойство, и оно загружается лениво, тогда Hibernate будет знать, что сиденье кожаное, но оно не может ретроспективно изменить класс прокси. Тем не менее, все данные есть. Сиденье будет отвечать как кожаное сиденье, если вы переопределили какие-либо методы.

Если вам действительно нужно передать этот объект в LeatherSeat, вы можете распаковать прокси с помощью http://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/engine/PersistenceContext.html#unproxy(java.lang.Объект)

Подробнее о том, почему прокси-сервером всегда будет Seat, а не LeatherSeat, см. В этом блоге: http://sessionfactory.blogspot.co.uk/2010/08/hacking-lazy-loaded-inheritance.html

Это кратко описано в документах гибернации здесь: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html#performance-fetching-proxies

Ответ №2:

Похоже, что если вы выполняете отложенную выборку, как вы делаете с getSeat , вы получите только родительский элемент, а не подкласс. Я попробовал этот же пример с FetchType .EAGER и getSeat корректно возвращают LeatherSeat .

Я не уверен, почему hibernate может получить автомобиль с кожаным сиденьем, когда для НЕТЕРПЕЛИВОЙ выборки, но hibernate, похоже, не может получить его при выполнении ЛЕНИВОЙ выборки. Похоже, там что-то сломано.

Существует запрос относительно столбцов дискриминатора для InheritanceType .ПРИСОЕДИНИЛСЯ там, где указано, что касается этого сценария. https://hibernate.onjira.com/browse/ANN-140 но запрос был отклонен, указав, что hibernate был слишком элегантным для использования дискриминатора для InheritanceType.Присоединился. Тем не менее, он не может корректно возвращать подклассы при отложенной выборке.

Тогда этот билет https://hibernate.onjira.com/browse/HHH-271?focusedCommentId=44089#comment-44089 является более конкретным для этого вопроса, и ответ там был: «Как мы предполагаем узнать, какой подкласс получить при ленивой выборке?»

Оба билета старые и были отклонены. Мне кажется, это проблема. Но сейчас вам придется перейти на другой тип наследования или использовать нетерпеливый тип выборки, поскольку это соответствует дизайну hibernate.