JPA inheritance @EntityGraph include optional associations of subclasses

后端 未结 4 890
广开言路
广开言路 2021-02-19 01:48

Given the following domain model, I want to load all Answers including their Values and their respective sub-children and put it in an AnswerDTO<

4条回答
  •  梦毁少年i
    2021-02-19 02:11

    I don't know what Spring-Data is doing there, but to do that, you usually have to use the TREAT operator to be able to access the sub-association but the implementation for that Operator is quite buggy. Hibernate supports implicit subtype property access which is what you would need here, but apparently Spring-Data can't handle this properly. I can recommend that you take a look at Blaze-Persistence Entity-Views, a library that works on top of JPA which allows you map arbitrary structures against your entity model. You can map your DTO model in a type safe way, also the inheritance structure. Entity views for your use case could look like this

    @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 getOption();
    }
    

    With the spring data integration provided by Blaze-Persistence you can define a repository like this and directly use the result

    @Transactional(readOnly = true)
    interface AnswerRepository extends Repository {
      List findAll();
    }
    

    It will generate a HQL query that selects just what you mapped in the AnswerDTO which is something like the following.

    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
    

提交回复
热议问题