0

Hall.java

@Entity
@Table(name="halls")
public class Hall {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @NotEmpty(message = "Hall name should be provided.")
    private String name;
    
    @NotNull
    @Min(value = 1, message = "Price must be greater than zero.")
    private Integer basicPrice;
    
    @NotNull
    @Min(value = 1, message = "capacity must be greater than zero.")
    private Integer capacity;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "city_id")
    private City city;

    // Other fields, constructor, getters and setters removed
}

City.java

@Entity
@Table(name="cities")
public class City {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @NotNull
    private String cityName;
    
    @OneToMany(mappedBy="city", fetch=FetchType.LAZY)
    private List<Hall> halls;

    // Other fields, constructor, getters and setters removed
}

I would like to let a user search halls based on filters in the front end. If a user passes a city it should return halls in that city regardless of price and capacity. The user can also search for halls with prices in a range. I have tried the following

HallRepo.java

@Repository
public interface HallRepo extends CrudRepository<Hall, Long> {
    
    @Query(value = "SELECT * FROM halls JOIN cities ON cities.id = halls.city_id WHERE "
            + "(cities.city_name = :cityName OR :cityName IS null) "
            + "AND (halls.basic_price BETWEEN :minP AND :maxP OR (:minP IS null AND :maxP IS null)) "
            + "AND (halls.capacity BETWEEN :minC AND :maxC OR (:minC IS null AND :maxC IS null))",
            nativeQuery = true)
    List<Hall> findByQuery(
            @Param("cityName") String cityName,
            @Param("minP") Integer minPrice,
            @Param("maxP") Integer maxPrice,
            @Param("minC") Integer minCapacity,
            @Param("maxC") Integer maxCapacity);
}

It's not Working. How to do it?

Jamal Harb
  • 11
  • 4
  • the idea is correct. how is it not working? do you get an error? do you just not get any results? what is the result of running the query in your database client? – Tom Elias Nov 21 '22 at 12:49
  • @TomElias I don't get a reasonable result. On browser, I get nested objects and in STS console I get this [31mERROR[0;39m [35m4308[0;39m [2m---[0;39m [2m[nio-8080-exec-5][0;39m [36ms.e.ErrorMvcAutoConfiguration$StaticView[0;39m [2m:[0;39m Cannot render error page for request [/halls/search] and exception [Could not write JSON: Infinite recursion (StackOverflowError); nested exception ... and way to many text. – Jamal Harb Nov 21 '22 at 13:04
  • @JamalHarb You are probably returning entities in your controller. `Hall` has a reference to `City` and `City` has a reference to `Hall` which causes an infinite mapping recursion. – void void Nov 21 '22 at 13:39
  • @voidvoid Not really. The references are for one to many relationship. – Jamal Harb Nov 21 '22 at 14:01
  • Ditch that method and use the criteria API instead, this is pretty easy with Spring Data and its `Predicate` interface. That way you can build a dynamic query based on the input. Instead of trying to shoehorn it all into a single query with a bunch of conditionals. – M. Deinum Nov 21 '22 at 14:01
  • Hall should not have a reference to his City. that is bad design in relational data. you can have a "connection table" with columns city ID, Hall ID – Tom Elias Nov 21 '22 at 15:03
  • @TomElias By "connection table" do you mean an intermediate table? I think you do that if the relationship is many to many. Can you elaborate more? – Jamal Harb Nov 21 '22 at 19:04
  • And by the way, I added @JsonIgnore to both classes and now the query works fine. I'm not quite sure what it has to do with the solution. – Jamal Harb Nov 21 '22 at 19:11

0 Answers0