代码之家  ›  专栏  ›  技术社区  ›  Ayoub k

Jpa存储库查询-java.lang.Object;无法转换为模型

  •  1
  • Ayoub k  · 技术社区  · 6 年前

    Movie 型号:

    @Entity
    public class Movie {
    
        private Long id;
        private String name;
        private Date releaseDate;
        private List<MovieCelebrity> movieCelebrities = new ArrayList<>();
    
        // getters & setters
    }
    

    MovieCelebrity 型号:

    @Entity
    public class MovieCelebrity extends DateAudit {
    
        private Long id;
        private String characterName;
        private Movie movie;
    
        // getters & setters
    }
    

    我想退票 身份证件 , 名称 , 发布日期 在回应中,类似这样的:

    {
        "id": 1,
        "name": Scarface,
        "releaseDate": 1983,
        "characterName": "Tony Montana"
    }
    

    所以我提出了以下问题:

    @Query("SELECT m.id, m.name, m.releaseDate, mc.characterName FROM Movie m JOIN m.movieCelebrities mc " +
           "WHERE mc.celebrity.id = :id AND mc.role = :role")
    Page<Movie> findMoviesByCelebrity(@Param("id") Long id, @Param("role") CelebrityRole role, Pageable pageable);
    

    但我得到了以下错误的回应:

    “java.base/[Ljava.lang.Object;无法转换为com.movies.mmdb.model.Movie“

    有一个解决方案可以在movie中创建一个构造函数,其中包含我需要返回的参数,并进行如下查询:

    @Query("SELECT new Movie(m.id, m.name, m.releaseDate, mc.characterName) FROM...)
    

    但是自从 在不同的模型里我不能做这样的构造器。

    3 回复  |  直到 6 年前
        1
  •  2
  •   df778899    6 年前

    除了DTO之外,SpringJPA中还有一些投影接口,实际上可以处理一些嵌套(参见 Spring Docs ). 这将是一个相当简单的选择,但你仍然不能轻易地强迫一个变成一个 Movie

    目前的另一个主要选择是 ResultTransformer 回到冬眠状态。例如,可以通过使用命名的JPA查询,然后在运行Hibernate查询API之前将其放回Hibernate查询API来访问它。

    @Entity
    @NamedQuery(name = "Movie.byCelebrity", 
        query = "SELECT m.id, m.name, m.releaseDate, mc.characterName FROM Movie m JOIN m.movieCelebrities mc " +
            "WHERE mc.role = :role")
    public class Movie {
    

    然后可以使用如下结果转换器调用:

        List<Movie> movies = entityManager
                .createNamedQuery("Movie.byCelebrity")
                .setParameter("role", role)
                .unwrap(org.hibernate.query.Query.class)
                .setResultTransformer(new MovieResultTransformer())
                .getResultList();
    

    通常,对于单层查询,可以使用 AliasToBeanResultTransformer 电影 .

    下面是一个示例结果转换器,它首先映射返回列(在“tuple”中,这是一个结果字段列表),然后通过

    public class MovieResultTransformer
            implements ResultTransformer {
        @Override
        public Object transformTuple(Object[] tuple,
                String[] aliases) {
            Movie movie = new Movie();
            movie.setId((Long) tuple[0]);
            movie.setName((String) tuple[1]);
            movie.setReleaseDate((Date) tuple[2]);
            MovieCelebrity movieCelebrity = new MovieCelebrity();
            movieCelebrity.setCharacterName((String) tuple[3]);
            movie.getMovieCelebrities().add(movieCelebrity);
            return movie;
        }
    
        @Override
        public List transformList(List collection) {
            Map<Long, Movie> movies = new LinkedHashMap<>();
            for (Object item : collection) {
                Movie movie = (Movie) item;
                Long id = movie.getId();
                Movie existingMovie = movies.get(id);
                if (existingMovie == null)
                    movies.put(id, movie);
                else
                    existingMovie.getMovieCelebrities()
                            .addAll(movie.getMovieCelebrities());
            }
            return new ArrayList<>(movies.values());
        }
    }
    

    值得注意的是 结果变压器 deprecated @todo develop a new approach to result transformers .

    显然,JPA中的预测领域仍然有点不完整。对于Hibernate6的建议是,他们将切换到功能接口和lambda风格的API,这将是一个很大的改进——在JPA中看到类似的ripple将是一件好事。

        2
  •  2
  •   Simon Martinelli    6 年前

    NEW的构造函数表达式只能用于dto(数据传输对象)。

    @Query("SELECT m FROM Movie m JOIN m.movieCelebrities mc " +
           "WHERE mc.celebrity.id = :id AND mc.role = :role")
    Page<Movie> findMoviesByCelebrity(@Param("id") Long id, @Param("role") CelebrityRole role, Pageable pageable);
    

    @Query("SELECT NEW your.package.MovieDTO(m.id, m.name, m.releaseDate, mc.characterName) FROM Movie m JOIN m.movieCelebrities mc " +
           "WHERE mc.celebrity.id = :id AND mc.role = :role")
    Page<MovieDTO> findMoviesByCelebrity(@Param("id") Long id, @Param("role") CelebrityRole role, Pageable pageable);
    

        3
  •  0
  •   Omid P    6 年前

    public class Movie {
    private String name;
    @Transient
    public String getCharacterName(){
    return getMovieCelebrities().iterator().next().getCharacterName();
    
    }
    }
    

    然后使用构造函数解决方案。