简体   繁体   中英

Need to return List of Custom Object using JPA @Query

I've a custom object

@Component
public class SaleReport {

    private Date date;
    private String customerName;
    private String phoneNo;
    private String productName;
    private Integer quantity;
    private Double totalAmount;

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public String getPhoneNo() {
        return phoneNo;
    }

    public void setPhoneNo(String phoneNo) {
        this.phoneNo = phoneNo;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public Integer getQuantity() {
        return quantity;
    }

    public void setQuantity(Integer quantity) {
        this.quantity = quantity;
    }

    public Double getTotalAmount() {
        return totalAmount;
    }

    public void setTotalAmount(Double totalAmount) {
        this.totalAmount = totalAmount;
    }
}

I need to return List of this object using a JpaRepository<Sale, Integer> The SaleRepository is as follow:

@Repository
public interface SaleRepository extends JpaRepository<Sale, Integer> {


    @Query(value = "SELECT B.order_date AS date, E.customer_name AS customerName, " +
            "E.phone_no AS phoneNo, D.product_name AS productName, C.quantity AS quantity, " +
            "C.total_price AS totalAmount " +
            "FROM SALE A " +
            "INNER JOIN A.quotation_id B " +
            "INNER JOIN B.quotation_id C " +
            "INNER JOIN C.product_id D " +
            "INNER JOIN B.customer_id E " +
            "WHERE (B.order_date BETWEEN :from_date AND :to_date)", nativeQuery = true)
    public List<SaleReport> getSaleReportByDate(@Param("from_date")String fromDate, @Param("to_date")String toDate);

}

Here is my Controller method:

@GetMapping("api/report/sale/{from_date}/{to_date}")
        public List<SaleReport> getSaleReportByDate(@PathVariable("from_date") String fromDate, @PathVariable("to_date") String toDate){
        return saleRepository.getSaleReportByDate(fromDate, toDate);
}

While I run the code it shows this error:

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown database 'a'
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_161]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_161]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_161]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_161]
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.47.jar:5.1.47]
    at com.mysql.jdbc.Util.getInstance(Util.java:408) ~[mysql-connector-java-5.1.47.jar:5.1.47]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:944) ~[mysql-connector-java-5.1.47.jar:5.1.47]

My DATABASE NAME is alright. It works perfectly while I request in other methods. Please suggest me an ideal solution.

1) You need to create a constructor for the SaleReport class that accepts all the parameters that you use in the select statement and in the exact order.

2) Alter your query so that you wrap the selected columns with a new statement:

@Query(value = "SELECT new org.mypackage.SaleReport(B.order_date AS date,"
                        + "E.customer_name AS customerName, "
                        + "E.phone_no AS phoneNo, D.product_name AS productName, 
                        + "C.quantity AS quantity, " +
                        + "C.total_price AS totalAmount) " +
            "FROM SALE A " +
            "INNER JOIN A.quotation B " +
            "INNER JOIN B.quotation C " +
            "INNER JOIN C.product D " +
            "INNER JOIN B.customer E " +
            "WHERE (B.order_date BETWEEN :from_date AND :to_date)") 

3) In my opinion you don't need a native query here and you can use HQL directly (changed joins).

Spring has an annotation called @SqlResultSetMapping This annotation can be used for above problem. Details about this annotation can be found from following link:

Annotation Type ConstructorResult

This is actually mapping a hibernate query result into a plain POJO Class. Thats what actually needed.

Example:

   Query q = em.createNativeQuery(
      "SELECT c.id, c.name, COUNT(o) as orderCount, AVG(o.price) AS avgOrder " +
      "FROM Customer c, Orders o " +
      "WHERE o.cid = c.id " +
      "GROUP BY c.id, c.name",
      "CustomerDetailsResult");

   @SqlResultSetMapping(
       name="CustomerDetailsResult",
       classes={
          @ConstructorResult(
               targetClass=com.acme.CustomerDetails.class,
                 columns={
                    @ColumnResult(name="id"),
                    @ColumnResult(name="name"),
                    @ColumnResult(name="orderCount"),
                    @ColumnResult(name="avgOrder", type=Double.class)
                    }
          )
       }
      )

Put @SqlResultSetMapping into top of any @Entity and make sure the datatype returning from database is same as your POJO Class datatype .

Hope this will help you. Enjoy :)

I hope this answer might help you !!

Sale is your entity class and SaleReport is pojo class.

public List<SaleReport> getSaleReportByDate(@Param("from_date")String fromDate, @Param("to_date")String toDate);

you can not return a pojo class list from database.It return entity class list. Use public List not public List

public List<Sale> getSaleReportByDate(@Param("from_date")String fromDate, @Param("to_date")String toDate);

@Repository
public interface SaleRepository extends JpaRepository<**Sale**, Integer>

you have to map Entity Class list to POJO class list.

Mapping of Entity class list to a pojo class list: As there are lot of ways to achieve this still Easiest solution is loop over entity class and set entity attribute to pojo attribute:

I don't suggest to use constructor because some times you may want to set only several fields not all fields of POJO class.

Arraylist<SaleReport> sr = new Arraylist<SaleReport>();
ArrayList<Sale> saleEntityList= saleRepository.getSaleReportByDate(fromDate,toDate);
for(Sale  s : saleEntityList){
    saleReport = new SaleReport();
    saleReport.setDate(s.getDate);
    //same for all attributes
    sr.add(saleReport);
} 
return sr;

Here sr is your POJO list.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM