2012-10-05 4 views
1

Nous utilisons JPA avec hibernate comme implémentation. Supposons que j'ai la DTO suivante:JPA/Hibernate + HQL/JPQL: sélectionnez DTO avec le paramètre BigDecimal

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

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

    // getters/setters 
} 

Je ne peux pas sembler se hiberner trouver correctement ce constructeur. J'ai d'abord essayé la requête suivante (le modèle est plus compliqué que cela, et j'ai besoin de récupérer des agrégations finalement (pas directement sur les entités), c'est pourquoi j'obtiens un DTO au lieu des entités):

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

Cependant, j'obtiens une exception org.hibernate.hql.ast.QuerySyntaxException: Unable to locate appropriate constructor on class.

La colonne remaining je sélectionne à partir est stocké sous forme d'un flotteur dans MSSQL (je sais, je sais que l'argent ne doit jamais être stocké sous forme de flotteurs, mais c'est un système existant où je ne peux pas simplement changer ce type de données) ..

en tant que test, j'ai essayé la requête suivante, mais avec la même exception que ci-dessus:

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

Alors ma question est la suivante: Comment puis-je faire hiberner/JPA trouver le constructeur approprié pour les deux requêtes ci-dessus? La propriété remaining est de type double sur l'entité Finances (pas ma décision).

+0

De quel type est le champ/colonneFinance restant? – RNJ

+0

J'ai mis à jour la question. –

+0

Pouvez-vous essayer d'inclure un constructeur par défaut? –

Répondre

2

Je ne sais pas pourquoi le cteur de BigDecimal n'est pas reconnu mais vous pouvez surcharger vos constructeurs

Si vous aviez

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

public SupplierInfoDto(String s, BigDecimal bd) { 
    //set fields 
} 

Non pas que si vous utilisez la double constructeur BigDecimal le nombre est basé sur un double donc peut encore avoir des erreurs d'arrondi. Il est généralement préférable d'utiliser la chaîne BigDecimal contstrctor

Par exemple

new BigDecimal("0.1") 

est plus précis que

new BigDecimal(0.1d) 

This article explique ce

+0

Oui, cela devrait fonctionner. Mais comme vous le signalez, le problème d'arrondi est toujours présent, ce que j'essaie d'éviter.Puis-je convertir/convertir un autre type en HQL? –

+0

@MortenJacobsen juste mis à jour la réponse à avoir String.valueOf (...) Cela peut aider bien que si la source dans la DB n'est pas bonne, vous ne pouvez pas attendre que le Java soit bon sans appliquer certaines règles – RNJ

0
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) 
+0

FYI, spécification JPA 2.0 en parle dans la section 4.8 SELECT Clause –

+0

Ce n'est pas vraiment utile .. La syntaxe n'est pas un problème puisque la requête passe. Je me demande pourquoi Hibernate ne peut pas ramasser sur le paramètre BigDecimal correctement. –

0

Pourquoi ne pas utiliser java.lang.Number comme le paramètre constructeur et créez le champ BigDecimal basé sur le .floatValue()/doubleValue() du paramètre.