Ok so I have two JPA Entities a Movie and a MovieRating. Similar to the below
@Entity
@Table(name = Movie.TABLE_NAME)
public class Movie {
static final String TABLE_NAME = "Movies";
@Id
@Column(name = "IMDB_ID")
private String imdbID;
@Column(name = "BOX_OFFICE_TAKINGS")
private int boxOfficeTakings;
@OneToMany(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MovieRating> ratings = new ArrayList<>();
// Getters and setters
}
And
@Entity
@Table(name = MovieRating.TABLE_NAME)
public class MovieRating {
static final String TABLE_NAME = "MovieRatings";
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID id;
private int rating;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "IMDB_ID")
private Movie movie;
//Getters and setters
}
I've written a @Query in the JPA Repository that should return results ordered by average rating descending and then box office value descending eg.
@Query("SELECT m FROM Movie m LEFT JOIN m.ratings r GROUP BY m ORDER BY AVG(r.rating) desc, m.boxOfficeTakings desc")
List<Movie> findTop10OrderedByBoxOfficeTakings(Pageable pageable);
So I'd expect for example a rated movie with a lower box office value to appear above an unrated movie with a higher box office value.
So I've written a test around this and it seems to work like I'd expect
@Test
public void testGetTop10ReturnsRatedMovieAboveUnratedMovieWithHigherValue() {
Movie movie1 = createMovieWithRatings(new Movie("tt000001", "The Godfather part 1", 2010, 268500000), null);
Movie movie2 = createMovieWithRatings(new Movie("tt000002", "The Godfather part 2", 2010, 93000000),
Arrays.asList(new MovieRating(10)));
movieRepository.saveAll(Arrays.asList(movie1, movie2));
List<MovieResponse> top10 = movieService.getTop10OrderedByBoxOfficeTakings();
List<String> expectedMovieIds = Arrays.asList(movie2.getImdbID(), movie1.getImdbID());
List<String> actualMovieIds = top10.stream().map(movie -> movie.getImdbID()).collect(Collectors.toList());
Assertions.assertEquals(expectedMovieIds, actualMovieIds);
}
private Movie createMovieWithRatings(Movie movie, List<MovieRating> ratings) {
if (ratings != null) {
ratings.forEach(rating -> movie.addRating(rating));
}
return movie;
}
However in practice when the code is running the order is movie1, and then movie2. Movie2 only moves above movie1 when it receives more than 1 rating. Why?