Search code examples
javahibernatejpahqljpql

JPA/Hibernate + HQL/JPQL: select DTO with BigDecimal parameter


We are using JPA with hibernate as the implementation. Suppose I have the following DTO:

public class SupplierInfoDto{
   private String supplierName;
   private BigDecimal remainingFinances;

   public SupplierInfoDto(String supplierName, BigDecimal remainingFinances){
       this.supplierName = supplierName;
       this.remainingFinances = remainingFinances;
   }

   // getters / setters
}

I cannot seem to get hibernate to properly find this constructor. I first tried the following query (the model is more complicated than this, and I need to fetch some aggregations eventually (not directly on the entities), that's why I'm fetching a DTO instead of the entities):

SELECT NEW com.company.dto.SupplierInfoDto(s.name, f.remaining)
FROM Supplier s INNER JOIN Finances f
WHERE s.id = :SupplierId

However, I get a org.hibernate.hql.ast.QuerySyntaxException: Unable to locate appropriate constructor on class exception.

The remaining column I'm selecting from is stored as a float in MSSQL (I know, I know money should never be stored as floats, but this is an existing system where I cannot just change this datatype)..

As a test, I tried the following query, but with the same exception as above:

SELECT NEW com.company.dto.SupplierInfoDto(s.name, NEW java.math.BigDecimal(10))
FROM Supplier s
WHERE s.id = :SupplierId

So my question is: How do I make hibernate/JPA find the appropriate constructor for the two queries above?

UPDATE: The remaining property is of type double on the Finances entity (not my decision).


Solution

  • I am not sure why the BigDecimal ctor is not being recognised but you could overload your constructors

    If you had

    public SupplierInfoDto(String s, Double d) {
       this(s, new BigDecimal(String.valueOf(d)));
    }
    
    public SupplierInfoDto(String s, BigDecimal bd) {
       //set fields
    }
    

    Not that if you use the BigDecimal double constructor the number is based on a double so can still have rounding errors. It is usually best to use BigDecimal string contstrctor

    For example

    new BigDecimal("0.1")
    

    is more precise than

    new BigDecimal(0.1d)
    

    This article explains this