2009-08-31 11 views
11

Czy istnieje sposób odwzorowania obliczonej właściwości za pomocą JPA?Mapowanie właściwości z JPA

Zakładając mam obiektu Invoice z jednym lub więcej InvoiceLineItems w nim, chcę mieć trwałą właściwość obliczona na klasy Invoice że daje mi całkowitą kwotę:

class Invoice { 
    ... 

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

Teraz mogę utworzyć chronione no-op setTotalAmount metoda, aby uczynić JPA szczęśliwym, ale zastanawiałem się, czy istnieje sposób, aby umożliwić WZP wiedzieć, że mapowanie jest tylko w jedną stronę i uniknąć tworzenia zbędnej metody setera.

Dzięki, Aleks

Odpowiedz

9

Co opisałeś nie jest obliczana nieruchomość w JPA znaczeniu. Obliczasz to samodzielnie w swojej metodzie - zaznacz tę metodę jako @Transient, a JPA ją zignoruje.

Jeśli naprawdę potrzebujesz wyliczonej właściwości (gdzie "obliczona" oznacza "wyliczona przez wyrażenie SQL"), musisz ją opatrzyć adnotacją zgodnie z twoim dostawcą JPA. Dla Hibernate chcesz to zrobić poprzez @Formula adnotacji:

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

Inni dostawcy mogą mieć swoje własne sposoby, aby skonfigurować ten; nie ma standardu JPA.

+0

Znakowanie nieruchomość jako @Transient nie pomoże mi. Nie chcę, aby JPA to zignorowało - chcę, aby całkowita kwota utrzymywała się w bazie danych, więc mogę prosić o nią bezpośrednio, bez konieczności agregowania informacji z tabeli podrzędnej. To, o co pytam, to jak utrzymać wyliczoną właściwość (w sensie Java, zupełnie niezwiązanym z wytrwałością) bez konieczności wprowadzania niepotrzebnego ustawiacza dla niej. –

+3

Twój przykład jest raczej dziwny. Jeśli ** przechowujesz ** tę wartość i pytasz o nią, dlaczego przeliczasz ją w swoim efekcie? Najważniejsze jest jednak to, że jeśli przypisujesz metodę getter (w przeciwieństwie do właściwości), musisz mieć odpowiedni program ustawiający (może być prywatny), aby JPA wypełniało tę wartość w twoim obiekcie. – ChssPly76

+0

Podany przeze mnie przykład jest nadmiernym uproszczeniem modelu domeny, z którym pracuję, który ma kilka poziomów relacji od jednej do wielu, z obliczoną właściwością na każdym poziomie, który zależy od dzieci. Obliczanie wartości w Javie w razie potrzeby jest znacznie łatwiejsze niż próba aktualizacji sumy, ponieważ obiekty potomne w (głębokiej) hierarchii są dodawane, usuwane lub modyfikowane, dlatego też ponownie je przeliczam. –

4

Być może do tego można użyć adnotacji PrePersist.

@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

Jest to z pewnością miło wiedzieć, dzięki. Jednak ja aby suma była aktualizowana za każdym razem, gdy na nią patrzę, nie tylko przed jej utrwaleniem, więc nie zadziała w moim konkretnym przypadku. –

+0

Braaaains ... To znaczy, dlaczego nie miałbyś po prostu prywatnego 'updateTotalAmount () 'metoda i wywołanie tego z' getTotalAmount() 'acccessor, a także' @ PrePersist'? Czy nie jest to, do czego służy getter? –

5

Wiem, że nekrologuję ten wątek, ale może to może pomóc komuś innemu.

Jeśli chcesz obliczyć wartość na odczycie, a @PostLoad adnotacja może być to, co chcesz:

@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

Nie tak naprawdę odpowiedź na pytanie OP, ale nawiasem mówiąc, po prostu prawo odpowiedź na MOJE pytanie, ponieważ chcę czegoś nieco innego od OP ... Dziękuję za opublikowanie tutaj! +1 –

Powiązane problemy