Reputation: 986
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).
Upvotes: 2
Views: 8792
Reputation: 69
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
Upvotes: 1
Reputation: 591
Why not use java.lang.Number as the constructor parameter and create the BigDecimal field based on the .floatValue() / doubleValue() of the parameter.
Upvotes: 0
Reputation: 15552
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
Upvotes: 5
Reputation: 59
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)
Upvotes: 0