1

I am currently developing a Spring Boot 2.5.5 app which needs to integrate some games. Each Game entity contains multiple GameProfile entities. Since the app and games are multilingual, we store all the generic fields in the GameProfile entity and all the others which are tied to the current language, are stored in an extra relation called GameProfileTranslation which references a Language entity.

Following are the three entities:

@Entity
@Table(name = "GAME_PROFILE")
@Getter
@Setter
public class GameProfile {

    @Id
    @Column(name = "GAME_PROFILE_ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "game_profile_seq")
    @SequenceGenerator(name = "game_profile_seq", allocationSize = 1, sequenceName="game_profile_sequence")
    private Long id;

    @Column(name = "IMAGE")
    private String image;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "GAME_ID")
    private Game game;

    @Column(name = "DIFFICULTY")
    private GameDifficulty difficulty;

    @OneToMany(mappedBy = "gameProfile", fetch = FetchType.LAZY)
    private Set<GameProfileTranslation> translations = new HashSet<>();

}
@Entity
@Table(name = "GAME_PROFILE_TRANSLATION")
@Getter
@Setter
public class GameProfileTranslation {

    @Id
    @Column(name = "GAME_PROFILE_TRANSLATION_ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "game_profile_translation_seq")
    @SequenceGenerator(name = "game_profile_translation_seq", allocationSize = 1, sequenceName="game_profile_translation_sequence")
    private Long id;

    @Column(name = "TITLE")
    private String title;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "GAME_PROFILE_ID")
    private GameProfile gameProfile;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "LANGUAGE_ID")
    private Language language;
}

@Entity
@Table(name = "LANGUAGE")
@Getter
@Setter
@NoArgsConstructor
public class Language {

    @Id
    @Column(name = "LANGUAGE_ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "CODE")
    private String code;

    @Column(name = "VALUE")
    private String value;

    @OneToMany(mappedBy = "language", fetch = FetchType.LAZY)
    private Set<User> users = new HashSet<>();

    @OneToMany(mappedBy = "language", fetch = FetchType.LAZY)
    private Set<GameProfileTranslation> gameProfileTranslations = new HashSet<>();

}

For the past two days I have been trying to create a repository method which returns all the GameProfile entities based on a languageId and a gameId given as @RequestParam to my Controller. To be more precise, I want to find all the GameProfiles and filter the nested translations object based on the language given.

I have tried two approaches, which are presented below. Both of these methods actually return all the GameProfile entities but the nested translations object contains all the GameProfileTranslation entities in the database. It is like the translations cannot be filtered by the language.

If I copy & paste the native query below in a Query Tool in pgAdmin I get the result I desire. However, using it through Spring Data returns all the translations.

My two approaches:

    @Query(
        nativeQuery = true,
        value = "SELECT * " +
                "FROM game_profile AS gp " +
                " INNER JOIN game_profile_translation AS gpt ON gp.game_profile_id = gpt.game_profile_id " +
                " INNER JOIN language AS l ON gpt.language_id = l.language_id " +
                "WHERE l.language_id = :languageId AND gp.game_id = :gameId ")
    List<GameProfile> findAllByGameIdAndLanguageId(@Param("gameId") Long gameId, @Param("languageId") Long languageId);

and

    @Query(value =  "SELECT gp " +
                    "FROM GameProfile AS gp JOIN FETCH gp.translations AS gpt " +
                    "WHERE gp.game.id = :gameId AND gpt.language.id = :languageId ")
    List<GameProfile> findAllByGameIdAndLanguageId(@Param("gameId") Long gameId, @Param("languageId") Long languageId);

TLDR: Both of these methods return all the GameProfile entites without filtering the nested translations object. To be more exact, the translations field contains all the translations available in the database regardless of the languageId.

Is there a way to return a List<GameProfile> entities with the translations object filtered by the languageId?

What I have tried:

  1. Filter child object in Spring Data Query
  2. Filtering out nested objects in JPA query
  3. Filter child object in Spring Data Query
tiempo
  • 121
  • 2
  • 14
  • 1
    That's not supported, your could remove the `private Set translations` association, make it `@Transient` and fetch it separately. Alternatively since you have `@ManyToOne` on `GameProfile` in `GameProfileTranslation` you can just fetch that entity instead and construct the dto from there. Look at similar answers: https://stackoverflow.com/questions/6919686/annotation-to-filter-results-of-a-onetomany-association https://stackoverflow.com/questions/57025040/spring-data-jpa-filter-children-in-onetomany – Igor Flakiewicz Jan 20 '22 at 10:27
  • 2
    Does this answer your question? [spring data jpa filter children in @OneToMany](https://stackoverflow.com/questions/57025040/spring-data-jpa-filter-children-in-onetomany) – Igor Flakiewicz Jan 20 '22 at 10:28
  • This is what I ended up doing but it seemed strange to me that you can't do it through Spring. Thanks for your help. – tiempo Feb 10 '22 at 09:01

0 Answers0