3
respostas

[Dúvida] ERRO na consulta

Estou com o seguinte error no console ao fazer a consulta:

Caused by: org.hibernate.query.SyntaxException: At 1:52 and token ')', no viable alternative at input 'SELECT new br.com.mlucas.freemovies.domain.Episodio(*) FROM Serie s JOIN s.episodios e WHERE e.titulo ILIKE :trechoEpisodio' [SELECT new br.com.mlucas.freemovies.domain.Episodio() FROM Serie s JOIN s.episodios e WHERE e.titulo ILIKE :trechoEpisodio]

Segue como está meu projeto:

// serieRepository.java.. 
    // cod omitido..
    
    @Query("SELECT e FROM Serie s JOIN s.episodios e WHERE e.titulo ILIKE %:trechoEpisodio%")
    List<Episodio> episodiosPorTrecho(@Param("trechoEpisodio") String trechoEpisodio);
    
    // cod omitido..
Main.java...
// cod omitido..

private void buscarEpisodioPorTrecho() {
        System.out.println("Qual o nome do episódio para busca?");
        var trechoEpisodio = leitura.nextLine();
        List<Episodio> episodiosEncontrados = repository.episodiosPorTrecho(trechoEpisodio);
        episodiosEncontrados.forEach(e ->
                System.out.printf("Série: %s Temporada %s - Episódio %s - %s\n",
                        e.getSerie().getTitulo(), e.getTemporada(),
                        e.getNumeroEpisodio(), e.getTitulo()));
    }

// cod omitido..
3 respostas

Oi, Márcio! Como vai?

O problema aqui é o uso incorreto de SELECT new na sua consulta. Quando se usa SELECT new, é obrigatório indicar um construtor existente na classe que está sendo instanciada. Mas, no seu código, você não precisa criar um novo objeto Episodio, pode apenas selecionar e diretamente.

Veja como ajustar:


@Query("SELECT e FROM Serie s JOIN s.episodios e WHERE e.titulo ILIKE %:trechoEpisodio%")
List<Episodio> episodiosPorTrecho(@Param("trechoEpisodio") String trechoEpisodio);

Além disso, o ILIKE não é suportado por padrão no JPQL. Para buscas case-insensitive, você pode usar LOWER e passar o parâmetro em letras minúsculas. Ajuste assim:


@Query("SELECT e FROM Serie s JOIN s.episodios e WHERE LOWER(e.titulo) LIKE LOWER(CONCAT('%', :trechoEpisodio, '%'))")
List<Episodio> episodiosPorTrecho(@Param("trechoEpisodio") String trechoEpisodio);

Sem acentuação:Este código faz uma busca por episódios cujo titulo contenha o trecho informado, ignorando maiúsculas e minusculas.

Exemplo no método buscarEpisodioPorTrecho:


private void buscarEpisodioPorTrecho() {
    System.out.println("Qual o nome do episodio para busca?");
    var trechoEpisodio = leitura.nextLine();
    List<Episodio> episodiosEncontrados = repository.episodiosPorTrecho(trechoEpisodio);
    episodiosEncontrados.forEach(e ->
        System.out.printf("Serie: %s Temporada %s - Episodio %s - %s\n",
            e.getSerie().getTitulo(), e.getTemporada(),
            e.getNumeroEpisodio(), e.getTitulo()));
}

Espero ter ajudado. Conte com o apoio do Fórum na sua jornada. Fico à disposição.

Abraços e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Fala Armano, eu seguir suas orientações e fiz os ajustes, porém o console me apresentou o mesmo erro, será que pode ser algum erro nas minhas entidades? vou enviar para voce dar uma revisada!

    package br.com.mlucas.freemovies.domain;

    import jakarta.persistence.*;

    import java.time.DateTimeException;
    import java.time.LocalDate;

    @Entity
    @Table(name = "episodios")
    public class Episodio {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String titulo;
        private LocalDate dataDeLancamento;
        private Integer numeroEpisodio;
        private Integer temporada;
        private Double avaliacao;


        @ManyToOne
        private Serie serie;

        public Episodio() {

        }
        public Episodio(Integer season, DadosEpisodio d) {
            this.temporada = season;
            this.titulo = d.tittle();
            this.numeroEpisodio = d.episode();
            try{
                this.avaliacao = Double.valueOf(d.imdbRating());
            } catch (NumberFormatException e) {
                this.avaliacao = 0.0;
            }
            try {
                this.dataDeLancamento = LocalDate.parse(d.released());
            } catch (DateTimeException e){
                this.dataDeLancamento = null;
            }
        }
         // cod omitido..
        }
package br.com.mlucas.freemovies.domain;
import br.com.mlucas.freemovies.service.traducao.ConsultaMyMemory;
import jakarta.persistence.*;

import java.util.ArrayList;
import java.util.List;
import java.util.OptionalDouble;

@Entity
@Table(name = "series")
public class Serie {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(unique = true)
    private String titulo;
    @Column(name = "totalDeTemporadas")
    private Integer totalSeasons;
    @Column(name = "avaliacao")
    private Double imdbRating;
    @Enumerated(EnumType.STRING) @Column(name = "genero")
    private Categoria genre;
    @Column(name = "atores")
    private String actors;
    private String poster;
    private String sinopse;
    @Column(name = "dataDeLancamento")
    private String released;

    @OneToMany(mappedBy = "serie", cascade = CascadeType.ALL,   fetch = FetchType.EAGER)
    private List<Episodio> episodios = new ArrayList<>();

    public Serie() {

    }
    public Serie(DadosSerie dadosSerie) {
        this.titulo = dadosSerie.tittle();
        this.totalSeasons = dadosSerie.totalSeasons();
        this.imdbRating = OptionalDouble.of(Double.valueOf(dadosSerie.imdbRating())).orElse(0);
        this.genre = Categoria.fromString(dadosSerie.genre().split(",")[0].trim());
        this.actors = dadosSerie.actors();
        this.poster = dadosSerie.poster();
        this.sinopse = ConsultaMyMemory.obterTraducao(dadosSerie.sinopse()).trim();
        this.released = dadosSerie.released();
    }

    // cod omitido..
}

Oi, Márcio!

Sobre sua última dúvida, o erro persiste mesmo após os ajustes na query, então o problema pode estar na forma como você tentou usar SELECT new na primeira versão — e isso pode ainda estar em algum lugar do seu código, talvez não no trecho que você mostrou agora.

A mensagem de erro indica que ainda existe uma consulta tentando fazer:

SELECT new br.com.mlucas.freemovies.domain.Episodio()

Esse tipo de sintaxe só funciona se a classe tiver um construtor público com os mesmos parâmetros usados na query, o que não é o caso da sua classe Episodio.

Solução: procure no seu projeto por qualquer outra query com SELECT new br.com.mlucas.freemovies.domain.Episodio(...) e remova esse trecho ou reescreva para apenas retornar a entidade. Você já fez isso corretamente neste método:

@Query("SELECT e FROM Serie s JOIN s.episodios e WHERE LOWER(e.titulo) LIKE LOWER(CONCAT('%', :trechoEpisodio, '%'))")
List<Episodio> episodiosPorTrecho(@Param("trechoEpisodio") String trechoEpisodio);

Agora, certifique-se de que não há nenhum outro lugar no projeto com SELECT new Episodio(...).

Use a busca do seu editor (Ctrl+Shift+F no IntelliJ ou VS Code) e procure por:

SELECT new br.com.mlucas.freemovies.domain.Episodio

Remova ou ajuste qualquer ocorrência como fizemos acima.

Fico à disposição!