Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jpa存储库查询-java.lang.Object;无法强制转换为模型_Java_Spring Boot_Spring Data Jpa_Spring Rest - Fatal编程技术网

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

Jpa存储库查询-java.lang.Object;无法强制转换为模型,java,spring-boot,spring-data-jpa,spring-rest,Java,Spring Boot,Spring Data Jpa,Spring Rest,电影型号: @Entity public class Movie { private Long id; private String name; private Date releaseDate; private List<MovieCelebrity> movieCelebrities = new ArrayList<>(); // getters & setters } @Entity public class M

电影
型号:

@Entity
public class Movie {

    private Long id;
    private String name;
    private Date releaseDate;
    private List<MovieCelebrity> movieCelebrities = new ArrayList<>();

    // getters & setters
}
@Entity
public class MovieCelebrity extends DateAudit {

    private Long id;
    private String characterName;
    private Movie movie;

    // getters & setters
}
我想在响应中返回id名称发布日期字符名,如下所示:

{
    "id": 1,
    "name": Scarface,
    "releaseDate": 1983,
    "characterName": "Tony Montana"
}
    List<Movie> movies = entityManager
            .createNamedQuery("Movie.byCelebrity")
            .setParameter("role", role)
            .unwrap(org.hibernate.query.Query.class)
            .setResultTransformer(new MovieResultTransformer())
            .getResultList();
因此,我提出了以下问题:

@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);

但是由于characterName在不同的模型中,我无法创建这样的构造函数。

带有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(“从电影m中选择m加入m.movieelebrities mc”+
“其中mc.名人.id=:id和mc.role=:role”)
PageFindMoviesBy名人(@Param(“id”)长id,@Param(“角色”)名人角色,可分页;
或者,如果要使用DTO:

@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);
@Query(“选择新的.package.MovieDTO(m.id,m.name,m.releaseDate,mc.characterName)从Movie m JOIN m.movieelebrities mc”+
“其中mc.名人.id=:id和mc.role=:role”)
PageFindMoviesBy名人(@Param(“id”)长id,@Param(“角色”)名人角色,可分页;

MovieDTO必须有一个构造函数,该构造函数从具有匹配类型的查询中获取所有参数。

为characterName创建一个临时getter方法,如下所示:

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

}
}

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

本质上,问题是如何将JPA查询投影到具有嵌套值的返回类型。这是目前JPA查询所没有的

除了DTO之外,SpringJPA中还有一些投影接口,实际上可以处理一些嵌套(请参阅)。这将是一个相当简单的选择,但您仍然无法轻松地将其强制为
电影

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

这是已声明的命名查询(根据问题示例中的可用类稍微简化):

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

{
    "id": 1,
    "name": Scarface,
    "releaseDate": 1983,
    "characterName": "Tony Montana"
}
    List<Movie> movies = entityManager
            .createNamedQuery("Movie.byCelebrity")
            .setParameter("role", role)
            .unwrap(org.hibernate.query.Query.class)
            .setResultTransformer(new MovieResultTransformer())
            .getResultList();
值得注意的是,
ResultTransformer
与Hibernate 5.2一起使用,源代码中有一条精彩的评论:
@todo开发一种新的结果转换器方法


显然,JPA的预测领域仍然有点不完整。Hibernate 6的建议是,他们将切换到功能接口和lambda风格的API,这将是一个巨大的改进-很高兴看到JPA中出现类似的涟漪。

此查询将创建一个有点复杂的响应,它将在响应中创建一个对象moviecelibrity,其中包含我需要的字符名。我想要的是没有MovieCelebrity对象的简单响应,根响应中只有characterName。请看问题中的回复“我不知道我想要什么,也许我没有什么意义。”在这种情况下,创建一个DTO类,该类有一个接受这些参数的构造函数。我更新了我的答案,使其不能被拍成电影。我更新了答案。返回值必须是MovieDTO,而不是Movie@Ayoubk,实体之间存在一对多关系,因此可能有多个字符。此外,在这种特殊情况下,最好使用DTO。如果您希望稍后使用结果列表对数据库进行更改,请使用Omid P提供的方法。
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());
    }
}