2009-08-31 28 views
11

Esiste un modo per mappare una proprietà calcolata utilizzando JPA?Mappatura delle proprietà calcolate con JPA

Supponendo che ho un oggetto Invoice con uno o più InvoiceLineItems all'interno di esso, voglio avere una proprietà calcolata persistente sulla classe Invoice che mi dà l'importo totale:

class Invoice { 
    ... 

    @Column(name = "TOTAL_AMOUNT") 
    public BigDecimal getTotalAmount() { 
     BigDecimal amount = BigDecimal.ZERO; 
     for (InvoiceLineItem lineItem : lineItems) { 
      amount = amount.add(lineItem.getTotalAmount()); 
     } 
     return amount; 
    } 
} 

Ora, ho potuto creare un protetto il metodo no-op setTotalAmount per rendere felice JPA, ma mi chiedevo se c'è un modo per far sapere a JPA che la mappatura è solo un modo e per evitare di creare un metodo setter superfluo.

Grazie, Aleks

risposta

9

quello che hai descritto non è una proprietà calcolata in JPA senso. Lo stai calcolando da solo con il tuo metodo: contrassegna il metodo come @Transient e JPA lo ignorerà.

Se è veramente necessaria una proprietà calcolata (dove "calcolato" significa "calcolato tramite l'espressione SQL"), è necessario annotarlo in base al proprio provider JPA. Per Hibernate si sarebbe farlo tramite @Formula annotazione:

@Formula("col1 * col2") 
public int getValue() { 
... 
} 

Altri provider possono avere i propri modi per configurare questo; non esiste uno standard JPA.

+0

Marcatura proprietà come @Transient non mi aiuterà. Non voglio che JPA lo ignori: voglio che l'importo totale sia mantenuto in un database, così posso interrogarlo direttamente senza dover aggregare le informazioni dalla tabella figlia. Quindi quello che sto chiedendo è come mantenere una proprietà calcolata (in senso Java, completamente estraneo alla persistenza) senza dover implementare setter non necessari. –

+3

Il tuo esempio è piuttosto strano allora. Se stai ** memorizzando ** questo valore e interrogandoci sopra, perché lo stai ricalcolando nel tuo getter? La linea di fondo, tuttavia, è che se si annota il metodo getter (al contrario della proprietà) è necessario avere un setter corrispondente (potrebbe essere privato) affinché JPA possa popolare quel valore sulla propria entità. – ChssPly76

+0

L'esempio che ho dato è una grossolana semplificazione del modello di dominio con cui sto lavorando, che ha diversi livelli di relazioni da uno a molti, con proprietà calcolate ad ogni livello che dipende dai bambini. Calcolare il valore in Java come necessario è significativamente più semplice rispetto al tentativo di aggiornare il totale come oggetti secondari in una gerarchia (profonda) vengono aggiunti, rimossi o modificati, motivo per cui lo ricalcolo. –

4

Forse l'annotazione PrePersist può essere utilizzata per questo.

@Column(name = "TOTAL_AMOUNT") 
private BigDecimal totalAmount; 

@PrePersist 
public void updateTotalAmount() { 
    BigDecimal amount = BigDecimal.ZERO; 
    for (InvoiceLineItem lineItem : lineItems) { 
     amount = amount.add(lineItem.getTotalAmount()); 
    } 
    this.totalAmount = amount; 
} 
+0

Questo è sicuramente bello sapere, grazie Tuttavia, io ho bisogno che il totale venga aggiornato ogni volta che lo guardo, non solo prima che venga mantenuto, quindi non funzionerà nel mio caso particolare. –

+0

Braaaains ... Voglio dire, perché non dovresti avere un 'updateTotalAmount privato () 'metodo, e lo chiamiamo dal' getTotalAmount() 'acccessor, oltre a' @ PrePersist'? Non è quello che serve a un getter? –

5

So che sto recuperando questa discussione, ma forse potrebbe aiutare qualcuno a uscire.

Se si vuole calcolare il valore in lettura, l'annotazione @PostLoad potrebbe essere ciò che si vuole:

@Transient 
private BigDecimal totalAmount; 

@PostLoad 
public void onPostLoad() { 
    BigDecimal amount = BigDecimal.ZERO; 
    for (InvoiceLineItem lineItem : lineItems) { 
     amount = amount.add(lineItem.getTotalAmount()); 
    } 
    this.totalAmount = amount; 
} 
+1

In realtà non è la risposta alla domanda degli OP, ma incidentalmente, solo la destra rispondi alla MIA domanda perché voglio qualcosa di leggermente diverso dall'OP ... Quindi grazie per averlo postato qui! +1 –

Problemi correlati