java - Tipo inscatolato vs primitivo come ID entità




database hibernate (4)

In JPA (implementazione di Hibernate) Quale tipo è meglio utilizzare come ID entità: tipo di box (ad es. Integer ) o tipo non registrato (es. int )?

Un amico ha detto che dovresti usare i tipi Boxed perché quando crei una nuova entità nel tuo programma, Hibernate vede che l'id è null e capisce che dovrebbe creare una nuova riga nel database (al contrario se id non è null Hibernate può aggiornare un riga esistente in databse).

Ma l'id delle mie entità era int e funzionava bene senza errori e sappiamo che il valore predefinito delle variabili di istanza primitive è 0 . Così ha detto che forse l'ibernazione tratta 0 come speciale e presuppone che l'oggetto sia nuovo.


Bene, usiamo non-primitivi e abbiamo una forte ragione per questo. Molti dei nostri campi int/Integer ad esempio, hanno un valore aziendale assoluto zero a zero per essere perfettamente validi. Pensa ad esempio ad un campo del debito: è più che OK se il campo è zero , il che significa che non hai debiti.

Il problema è che con le primitive, zero è un valore predefinito, quindi potresti dimenticarti di impostarlo per esempio tramite un setDebt , quindi potrebbe raggiungere il tuo database con un valore che non avresti mai voluto andare lì. Per questo motivo usiamo Integer con alcune convalide che non dovrebbero mai essere nulle per esempio; ma anche se dimentichiamo di aggiungere validazioni appropriate, quel codice si romperà potenzialmente con una NullPointerException (preferibilmente nei test) e mi piace NullPointerException più che valori incoerenti nel database.


Gli identificatori univoci di entità e raccolte possono essere di qualsiasi tipo di base tranne binario, blob e clob. (Sono ammessi anche identificatori composti, vedi sotto).

I tipi di valori di base hanno costanti di tipo corrispondenti definite su org.hibernate.Hibernate. Ad esempio, Hibernate.STRING rappresenta il tipo di stringa.


Possiamo pensare in questo modo:

Quando abbiamo un valore x :: Int , allora 'x' è un calcolo che, una volta valutato, restituirà un Int o sarà inferiore (indefinito).

Quando il programma viene eseguito e x viene valutato, supponiamo che si valuti di un Int reale (non inferiore). Quindi in futuro ogni volta che viene valutato x, invece di ripetere l'intero calcolo, vogliamo solo ottenere il valore che abbiamo calcolato in precedenza.

Quello che facciamo per ottenere ciò è sostituire a thunk (calcolo) che calcola x con un thunk che restituisce semplicemente il valore che è stato calcolato prima.

Il problema è che ogni volta che hai bisogno di ottenere x in futuro, devi seguire questo puntatore al codice (banale) che restituisce un valore. È costoso se hai bisogno di questi valori frequentemente.

Inserisci valori non in scatola. Un valore unboxed è solo quel valore di basso livello, non racchiuso all'interno di un thunk. Ciò significa che è rigoroso, nel senso che non può essere indefinito senza che il tuo programma necessariamente muoia.


Preferisco il tipo di box nel modello di entità perché ciò dà la flessibilità di usare il tipo di box in generici. Ad esempio, qui il modello di entità può avere solo il tipo che si estende a Serializable per id. Sarà utile in seguito nel livello di servizio in cui possiamo eseguire varie operazioni sulla chiave primaria.

public interface BaseEntity<E extends Serializable> extends Serializable {
  E getId();
}

Il modello di entità potrebbe essere come:

@Entity
public class PhoneNumber implements BaseEntity<Long> {
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "PHONE_NUMBER_ID")
  private Long id;




orm