How could I fix this error: Cannot create TypedQuery for query with more than one return using requested result type?

Viewed 796

I have the following class:

public class House {
    @Id
    @GeneratedValue
    private long id;
    private String title;
    private String description;
    private String city;
    private double price;
    private String phoneNumber;
}

I need to make a @GetMapping, where I have to get every attribute of a house except it's city. I tried this:

This is in my repository:

public House findByIdButCity(long id) {
    return em.createQuery("SELECT h.title, h.description, h.price FROM House h WHERE h.id = :id", House.class).setParameter("id", id).getSingleResult();
}

And this is in my controller:

@GetMapping("{id}")
public ResponseEntity<House> getAttributesButCityById(@PathVariable long id) {
    House house = houseRepository.findByIdButCity(id);
    if (house == null)
        return ResponseEntity.notFound().build();
    else
        return ResponseEntity.ok(property);
}
2 Answers

Instead of filter the fields in the select, get all the information of a house and then map it to an object in the controller with only the information that you want to return, this way you also will decouple your database model from your API:

public House findByIdButCity(long id) {
    return em.createQuery("SELECT h FROM House h WHERE h.id = :id", House.class).setParameter("id", id).getSingleResult();
}

public class HoouseDto {
   private String title;
   private String description;
   private double price;
}

@GetMapping("{id}")
public ResponseEntity<HouseDto> getAttributesButCityById(@PathVariable long id) {
    House house = houseRepository.findByIdButCity(id);
    if (house == null)
        return ResponseEntity.notFound().build();
    else {
       HouseDto houseDto = mapper.toDto(house)
        return ResponseEntity.ok(houseDto);
     }
}

} You can use mapstruct to make the mapper or you can create a class with a static method to do it

Mapper example

public class HouseMapper {
    
    public static HouseDto toDto(House house) {
      HouseDto houseDto = new HouseDto();
      houseDto.setTitle(house.getTitle());
      houseDto.setDescription(house.getDescription());
      houseDto.setPrice(house.getDescription());
      return houseDto;
    }

You can do more easily if you include the mapstruct with spring because you only have to define an interface and it will create the implementation mapping the attributes that with same names.

Here is an example: https://www.baeldung.com/mapstruct

try changing your query to

SELECT h FROM House h WHERE h.id = :id
Related