11 Stimmen

Mapping berechneter Eigenschaften mit JPA

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

Angenommen, ich habe eine Invoice Objekt mit einem oder mehreren InvoiceLineItems möchte ich eine dauerhafte berechnete Eigenschaft in der Invoice Klasse, die mir den Gesamtbetrag liefert:

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 könnte ich ein geschütztes No-op erstellen setTotalAmount Methode, um JPA glücklich zu machen, aber ich habe mich gefragt, ob es eine Möglichkeit gibt, JPA wissen zu lassen, dass die Zuordnung nur in eine Richtung geht und eine überflüssige Setter-Methode zu vermeiden.

Danke, Aleks

10voto

ChssPly76 Punkte 97241

Was Sie beschrieben haben, ist keine berechnete Eigenschaft im Sinne von JPA. Sie berechnen es selbst innerhalb Ihrer Methode - markieren Sie diese Methode einfach als @Transient und JPA wird es ignorieren.

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

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

Andere Anbieter haben möglicherweise ihre eigenen Möglichkeiten, dies zu konfigurieren; es gibt keinen JPA-Standard.

0 Stimmen

Die Kennzeichnung der Eigenschaft als @Transient hilft mir nicht. Ich möchte nicht, dass JPA sie ignoriert - ich möchte, dass der Gesamtbetrag in einer Datenbank gespeichert wird, damit ich ihn direkt abfragen kann, ohne Informationen aus der untergeordneten Tabelle aggregieren zu müssen. Meine Frage ist also, wie man eine berechnete Eigenschaft (im Sinne von Java, völlig unabhängig von der Persistenz) persistieren kann, ohne unnötige Setter dafür zu implementieren.

3 Stimmen

Ihr Beispiel ist also ziemlich seltsam. Wenn Sie Speicherung von diesen Wert und Abfrage auf sie, warum sind Sie es in Ihrem Getter neu berechnen? Die Quintessenz ist jedoch, dass Sie, wenn Sie eine Getter-Methode (im Gegensatz zu einer Eigenschaft) annotieren, einen entsprechenden Setter haben müssen (dieser kann privat sein), damit JPA diesen Wert in Ihrer Entität auffüllt.

0 Stimmen

Das Beispiel, das ich gegeben habe, ist eine grobe Vereinfachung des Domänenmodells, mit dem ich arbeite und das mehrere Ebenen von eins-zu-viele-Beziehungen hat, mit berechneten Eigenschaften auf jeder Ebene, die von Kindern abhängen. Die Berechnung des Werts in Java ist wesentlich einfacher als der Versuch, die Gesamtsumme zu aktualisieren, wenn untergeordnete Objekte in einer (tiefen) Hierarchie hinzugefügt, entfernt oder geändert werden, weshalb ich sie neu berechne.

5voto

LeChe Punkte 1248

Ich weiß, dass ich diesen Thread necro-ing, aber vielleicht könnte es jemandem helfen.

Wenn Sie den Wert beim Lesen berechnen wollen, muss der @PostLoad Anmerkung könnte das 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 Stimmen

Eigentlich nicht die Antwort auf die Frage des Auftraggebers, aber übrigens genau die richtige Antwort auf MEINE Frage, da ich etwas anderes als der Auftraggeber möchte... Also danke, dass du es hier gepostet hast! +1

4voto

Jörn Horstmann Punkte 32716

Vielleicht kann die PrePersist-Anmerkung hierfür 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 Stimmen

Das ist auf jeden Fall gut zu wissen, danke. Allerdings brauche ich die Summe zu aktualisieren, wann immer ich es sehe, nicht nur, bevor es persistiert wird, so dass es nicht in meinem speziellen Fall zu arbeiten.

0 Stimmen

Braaaains... Ich meine, warum solltest du nicht einfach eine private updateTotalAmount() Methode, und rufen Sie diese von der getTotalAmount() Prozessor, sowie @PrePersist ? Ist ein Getter nicht genau dafür da?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X