Я не знаю, что там делает Spring-Data, но для этого обычно нужно использовать оператор TREAT
, чтобы получить доступ к подассоциации, но реализация этого оператора довольно глючная. Hibernate поддерживает неявный доступ к свойствам подтипов, который вам здесь нужен, но, очевидно, Spring-Data не может справиться с этим должным образом. Я могу порекомендовать вам взглянуть на Blaze-Persistence Entity-Views , библиотеку, которая работает поверх JPA и позволяет сопоставлять произвольные структуры с вашей моделью сущностей. Вы можете отобразить свою модель DTO безопасным способом, а также структуру наследования. Представления сущностей для вашего варианта использования могут выглядеть следующим образом
@EntityView(Answer.class)
interface AnswerDTO {
@IdMapping
Long getId();
ValueDTO getValue();
}
@EntityView(Value.class)
@EntityViewInheritance
interface ValueDTO {
@IdMapping
Long getId();
}
@EntityView(TextValue.class)
interface TextValueDTO extends ValueDTO {
String getText();
}
@EntityView(RatingValue.class)
interface RatingValueDTO extends ValueDTO {
int getRating();
}
@EntityView(MCValue.class)
interface TextValueDTO extends ValueDTO {
@Mapping("selected.id")
Set<Long> getOption();
}
Благодаря интеграции данных пружины, предоставляемой Blaze-Persistence, вы можете определить подобное хранилище и напрямую использовать результат
@Transactional(readOnly = true)
interface AnswerRepository extends Repository<Answer, Long> {
List<AnswerDTO> findAll();
}
Он сгенерирует HQL-запрос, который выберет именно то, что вы отобразили в AnswerDTO
, что-то вроде следующего:
SELECT
a.id,
v.id,
TYPE(v),
CASE WHEN TYPE(v) = TextValue THEN v.text END,
CASE WHEN TYPE(v) = RatingValue THEN v.rating END,
CASE WHEN TYPE(v) = MCValue THEN s.id END
FROM Answer a
LEFT JOIN a.value v
LEFT JOIN v.selected s