简体   繁体   中英

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).

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

class named X  with a constructor that takes two parameters. The types of the parameters from the SELECT clause must match the signature defined in the class.

Syntax for the SELECT clause:

select_clause ::= SELECT [DISTINCT] select_expression
    {, select_expression}*
    select_expression ::=
    single_valued_path_expression |
    aggregate_expression |
    identification_variable |
    OBJECT(identification_variable) |
    constructor_expression
    constructor_expression ::=
    NEW constructor_name ( constructor_item {, constructor_item}* )
    constructor_item ::= single_valued_path_expression |
    aggregate_expression
    aggregate_expression ::=
    { AVG | MAX | MIN | SUM }
    ([DISTINCT] state_field_path_expression) |
    COUNT ([DISTINCT] identification_variable |
    state_field_path_expression |
    single_valued_association_path_expression)

为什么不使用 java.lang.Number 作为构造函数参数并根据参数的 .floatValue() / doubleValue() 创建 BigDecimal 字段。

Try this:

CAST(f.remaining AS big_decimal)

According to https://docs.jboss.org/hibernate/orm/3.5/reference/en/html/queryhql.html

cast(... as ...), where the second argument is the name of a Hibernate type , and extract(... from ...) if ANSI cast() and extract() is supported by the underlying database

And https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/type/package-summary.html

BigDecimalType big_decimal : A type that maps an SQL NUMERIC to a java.math.BigDecimal

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