2009-08-31 13 views
11

Gibt es eine Möglichkeit, eine berechnete Eigenschaft mit JPA abzubilden?Mapping berechneter Eigenschaften mit JPA

Angenommen, ich habe ein Invoice Objekt mit einem oder mehreren InvoiceLineItems innerhalb es, ich will auf der Invoice Klasse eine persistente berechnete Eigenschaft haben, die mir die Gesamtmenge gibt:

class Invoice { 
    ... 

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

Nun, ich könnte ein erstellen protected no-op setTotalAmount Methode, um JPA glücklich zu machen, aber ich frage mich, ob es eine Möglichkeit gibt, JPA wissen zu lassen, dass das Mapping nur eine Möglichkeit ist und die Erstellung einer überflüssigen Setter-Methode zu vermeiden.

Danke, Aleks

Antwort

9

Was haben Sie nicht eine berechnete Eigenschaft in JPA Sinne beschrieben ist. Sie berechnen es selbst innerhalb Ihrer Methode - markieren Sie einfach diese Methode als @Transient und JPA ignoriert sie.

Wenn Sie wirklich eine berechnete Eigenschaft benötigen (wobei "berechnet" bedeutet "über SQL-Ausdruck berechnet"), müssen Sie sie entsprechend Ihrem JPA-Anbieter kommentieren. Für Hibernate würden Sie tun, dass über @Formula Anmerkung:

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

Andere Anbieter ihre eigenen Wege, dies zu konfigurieren haben kann; Es gibt keinen JPA-Standard.

+0

Kennzeichnung Eigenschaft als @Transient wird mir nicht helfen. Ich möchte nicht, dass JPA es ignoriert - ich möchte, dass die Gesamtmenge in einer Datenbank gespeichert wird, so dass ich direkt danach fragen kann, ohne Informationen aus der Kindtabelle aggregieren zu müssen. Also was ich frage ist, wie man eine berechnete Eigenschaft persistent (in Java Sinn, völlig unabhängig von Persistenz), ohne unnötige Setter für sie implementieren. –

+3

Ihr Beispiel ist dann eher seltsam. Wenn Sie diesen Wert ** speichern und abfragen, warum berechnen Sie ihn in Ihrem Getter neu? Die Quintessenz ist jedoch, dass Sie, wenn Sie die Getter-Methode (im Gegensatz zur Eigenschaft) annotieren, einen entsprechenden Setter haben müssen (er kann privat sein), damit JPA diesen Wert für Ihre Entität auffüllen kann. – ChssPly76

+0

Das Beispiel, das ich gab, ist grobe übermäßige Vereinfachung des Domänenmodells, mit dem ich arbeite, die mehrere Ebenen von Beziehungen zwischen eins und vielen haben, mit berechneten Eigenschaften auf jeder Ebene, die von Kindern abhängen. Den Wert in Java nach Bedarf zu berechnen ist wesentlich einfacher als zu versuchen, die Summe zu aktualisieren, da untergeordnete Objekte in einer (tiefen) Hierarchie hinzugefügt, entfernt oder geändert werden, weshalb ich sie neu berechne. –

4

Möglicherweise kann hierfür die PrePersist-Annotation verwendet werden.

@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

Das ist definitiv nett zu wissen, danke. Allerdings habe ich Die Summe muss aktualisiert werden, wann immer ich sie ansehe, nicht nur bevor sie dauerhaft bleibt, also wird es in meinem speziellen Fall nicht funktionieren. –

+0

Braaaains ... Ich meine, warum hättest du nicht einfach einen privaten 'updateTotalAmount () 'Methode, und rufen Sie das von der' getTotalAmount() 'acccessor, sowie' @ PrePersist 'Ist das nicht, was ein Getter ist? –

5

Ich weiß, dass ich diesen Thread necro-ing, aber vielleicht kann es jemand heraus helfen.

Wenn Sie den Wert auf Lese berechnen möchten, die @PostLoad Anmerkung könnte sein, was Sie wollen:

@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

Nicht wirklich die Antwort auf die OPs Frage, aber nebenbei, genau das Richtige Beantworte MEINE Frage, da ich etwas anderes als OP möchte ... Danke, dass du es hier gepostet hast! +1 –

Verwandte Themen