Хочу получить полную информацию о лоте с последним ставившим и текущей ценой используя классы DTO


@Entity
@Table(name = "lot")
public class Lot {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Enumerated(EnumType.STRING)
    private Status status;

    private String title;
    @Min(1)
    @Max(4096)
    private String description;
    @Min(1)
    @Max(100)
    private Integer startPrice;
    @Min(1)
    @Max(100)
    private Integer bidPrice;
    @OneToMany(mappedBy = "lot",fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    private List<Bid>bidList;

    public Lot(Status status, String title, String description, Integer startPrice, Integer bidPrice) {
        this.status = Status.CREATED;
        this.title = title;
        this.description = description;
        this.startPrice = startPrice;
        this.bidPrice = bidPrice;
    }


    public Lot() {
    }

@Entity
@Table(name ="bid" )
public class Bid {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String bidderName;
    private LocalDateTime timeStamp;
    @ManyToOne
    @JoinColumn(name = "lot_id")
    private Lot lot;

    public Bid(String bidderName, LocalDateTime timeStamp, Lot lot) {
        this.bidderName = bidderName;
        this.timeStamp = timeStamp;
        this.lot = lot;
    }

    public Bid() {
    }

public class FullLotDTO {
    private Long id;
    private String status;
    private String title;
    private String description;

    private Integer startPrice;
    private Integer bidPrice;
    private Integer currentPrice;
   
    private BidderDTO bidList;

    public FullLotDTO(Long id, String status, String title, String description, Integer startPrice, Integer bidPrice, Integer currentPrice, BidderDTO bidList) {
        this.id = id;
        this.status = status;
        this.title = title;
        this.description = description;
        this.startPrice = startPrice;
        this.bidPrice = bidPrice;
        this.currentPrice = currentPrice;
        this.bidList = bidList;
    }

public class BidderDTO {
    private String bidderName;
    private LocalDateTime timeStamp;


    public BidderDTO(String bidderName, LocalDateTime timeStamp) {
        this.bidderName = bidderName;
        this.timeStamp = timeStamp;
    }

@Repository
public interface BidRepository extends JpaRepository<Bid, Integer> {

   
 @Query("SELECT new ru.skypro.lessons.springboot.auction.dto.FullLotDTO " +
            "(l.id, " +
            "l.status, " +
            "l.title, " +
            "l.description, " +
            "l.startPrice, " +
            "l.bidPrice, " +
            "SUM(l.startPrice * l.bidPrice) AS currentPrice, " +
            "b.bidderName, b.timeStamp) " +
            "FROM Bid b JOIN b.lot l " +
            "WHERE l.id = :id AND b.timeStamp =  (SELECT MAX(b2.timeStamp) FROM Bid b2 WHERE b2.lot = l)" +
            "GROUP BY l.id, l.status, l.title, l.description, l.startPrice, l.bidPrice,b.bidderName, b.timeStamp")
    FullLotDTO InfoFullLot(@Param("id") Long id);

Имеется две связанные таблицы таблицы и класс DTO который использую для передачи данных и ожидаю возврат информацию о лоте с последним ставившим и текущей ценой, запрос еще должен подсчитать и выдать сумму .

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

.IllegalStateException: Cannot instantiate class 'ru.skypro.lessons.springboot.auction.dto.FullLotDTO' (it has no constructor with signature [java.lang.Long, ru.skypro.lessons.springboot.auction.model.Status, java.lang.String, java.lang.String, java.lang.Integer, java.lang.Integer, java.lang.Long, java.lang.String, java.time.LocalDateTime], and not every argument has an alias)

Застрял на моменте с составлением запрос к БД так как нету полного понимания как строить запрос.

Подскажите как правильно реализовать запрос.


Ответы (1 шт):

Автор решения: MrFylypenko

В тесте ошибки сказано and not every argument has an alias что нет алиасов на полученные колонки (l.id as id и т.д). Формат запроса должен выглядеть так:

 @Query("SELECT new ru.skypro.lessons.springboot.auction.dto.FullLotDTO " +
            "(l.id as id, " +
            "l.status as status, " +
            "l.title as title, " +
            "l.description as description, " +
            "l.startPrice as startPrice, " +
            "l.bidPrice as bidPrice, " +
            "SUM(l.startPrice * l.bidPrice) AS currentPrice, " +
            "b.bidderName as bidderName, " + // должно присутствовать в конструкторе
            "b.timeStamp as timeStamp) " + // должно присутствовать в конструкторе
            "FROM Bid b JOIN b.lot l " +
            "WHERE l.id = :id AND b.timeStamp =  (SELECT MAX(b2.timeStamp) FROM Bid b2 WHERE b2.lot = l)" +
            "GROUP BY l.id, l.status, l.title, l.description, l.startPrice, l.bidPrice,b.bidderName, b.timeStamp")
 FullLotDTO InfoFullLot(@Param("id") Long id);

Конструктор DTO лучше сделать только с примитивными данными, и 2 последних поля которые относятся к другой таблице, лучше преобразовать в объект внутри конструктора:

public class FullLotDTO {
    private Long id;
    private String status;
    private String title;
    private String description;
    private Integer startPrice;
    private Integer bidPrice;
    private Long currentPrice;
   
    private BidderDTO bidList;

    public FullLotDTO(Long id, String status, String title, String description, 
    Integer startPrice, Integer bidPrice, 
    Long currentPrice, 

    // BidderDTO bidList // этого не должно быть в параметрах конструктора

    String bidderName, // поле из запроса
    LocalDateTime timeStamp //поле из запроса
    ) {
        this.id = id;
        this.status = status;
        this.title = title;
        this.description = description;
        this.startPrice = startPrice;
        this.bidPrice = bidPrice;
        this.currentPrice = currentPrice;
    
        this.bidList = new BidderDTO(bidderName, timeStamp); // создаем объект тут
    }
}
→ Ссылка