Не удалось преобразовать тип [java .lang.String] в тип [java .lang.Long] для Spring JPA? - PullRequest
0 голосов
/ 09 июля 2020

У меня проблема с реализацией двух сущностей, названных для Country и State в Spring JPA.

Я написал код для представления сущностей Country и State, показанных ниже.

Country Entity

@Entity
@Table(name="COUNTRY",catalog ="SPRINGANGULAR")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = {"id","code","countryName"}, exclude = "states")
public class Country {

    @Id
    @SequenceGenerator(name="COUNTRY_SEQ", sequenceName="COUNTRY_SEQ", allocationSize=1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="COUNTRY_SEQ")
    @Column(name="ID", nullable = false)
    private long id;
    
    @Column(name="CODE")
    private String code;
    
    @Column(name="COUNTRY_NAME")
    private String countryName;
    
    @OneToMany(fetch=FetchType.LAZY,mappedBy="country",
            cascade= CascadeType.ALL)
    private Set<State> states = new HashSet<State>();

    public Country(String code, String countryName) {
        super();
        this.code = code;
        this.countryName = countryName;
    }
    
}

State Entity

@Entity
@Table(name="STATE",catalog ="SPRINGANGULAR")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = {"id", "stateName"})
public class State {

    @Id
    @SequenceGenerator(name="STATE_SEQ", sequenceName="STATE_SEQ", allocationSize=1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="STATE_SEQ")
    @Column(name="ID", nullable = false)
    private long id;
    
    @Column(name="STATE_NAME")
    private String stateName;
    
    @ManyToOne(fetch=FetchType.LAZY,cascade= CascadeType.ALL)
    @JoinColumn(name = "COUNTRY_ID", nullable = false)
    private Country country;

    public State(String stateName, Country country) {
        super();
        this.stateName = stateName;
        this.country = country;
    }
    
}

Затем я создаю State Reporistory для получения состояний по коду страны.

@CrossOrigin("http://localhost:4200")
@RepositoryRestResource(collectionResourceRel = "states", path = "states")
public interface StateRepository extends JpaRepository<State, Long>{

    @Query("SELECT s FROM State s \n" + 
           "LEFT JOIN Country c ON c.id = c.id \n" + 
           "WHERE c.code = :code \n" + 
           "ORDER BY s.id ASC")
    List<State> findByCountryCode(@RequestParam("code") String code);
}

Затем я пишу URL-адрес подключения в Postman, чтобы проверить, он работает.

http://localhost:8080/api/states/findByCountryCode?code=BR

Выдает ошибку

Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'findByCountryCode'; nested exception is java.lang.NumberFormatException: For input string: "findByCountryCode"

Как я могу исправить проблему?

Ответы [ 3 ]

1 голос
/ 09 июля 2020

Ваш запрос представляет собой смесь нативного SQL и JPQL, определенно недопустим. Вот действительный:

@Query("SELECT s FROM State s \n" + 
           "WHERE s.country.code = :code \n" + 
           "ORDER BY s.id ASC")

Нет необходимости в явном левом соединении, это делается выражением s.country.

Кроме того, не существует такой вещи, как LEFT JOIN ON в JPQL. Здесь - несколько примеров соединения

Кроме того, URL-адрес должен быть примерно таким:

http://localhost:8080/states/search/findByCountryCode?code=BR

Вам не хватает search в качестве пути элемент.

0 голосов
/ 09 июля 2020

Решение показано ниже.

Я ошибочно использую этот URL http://localhost:8080/api/states/findByCountryCode?code=BR

Преобразовать URL

http://localhost:8080/api/states/findByCountryCode?code=BR`

в

http://localhost:8080/api/states?code=BR
0 голосов
/ 09 июля 2020

Мне кажется, проблема с контроллером REST .
Я предполагаю, что у вас есть сопоставление для /api/states/{id} где-то, например:

@RestController
@RequestMapping(path = "api/states/")
public class StateController {

    @GetMapping("/{id}")
    public State getState(@PathVariable("id") long id) {
       ...
    }
}

Когда вы звоните /api/states/findByCountryCode?code=BR, затем он интерпретирует findByCountryCode как переменную пути id типа long, что приведет именно к этому исключению:

NumberFormatException: For input string: "findByCountryCode"

Решение:

  • либо ограничивает параметр пути id шаблоном регулярного выражения (numeri c), либо
  • использует другой путь для запроса состояний (например, /api/states?code=BR)

Последний шаблон является общим стандартом для перечисления и поиска ресурсов :

  • без параметров запроса: перечислить все
  • с параметрами запроса: сопоставление списка -> функция поиска

Примерно так:

    @GetMapping("/")
    public List<State> find(@RequestParam(value = "code", required = false) String code) {
       if (code != null) {
           // find by code
       } 
       else {
           // list all
       }
    }
...