5.1 Ora modificării datelor

Când stocați diferite înregistrări într-o bază de date timp de mulți ani, apar adesea două întrebări:

  • Când a fost adăugată această intrare în baza de date?
  • Când a fost modificată ultima dată această intrare?

Acestea sunt sarcini atât de frecvente încât două coloane sunt adăugate la aproape fiecare tabel din baza de date:

  • timpul_creat
  • updated_time

Primul stochează data și ora la care a fost creată înregistrarea, iar al doilea stochează data și ora la care a fost modificată ultima dată. Și fiecare clasă de Entitate are câmpuri:


@Entity
@Table(name = "entities")	
public class Entity {
  ...
 
  @Column(name="created_time")
  private Date created;
 
  @Column(name="updated_time")
  private Date updated;
}

Hibernate poate face toată munca de a controla când obiectele din baza de date sunt actualizate cu două adnotări @CreationTimestampși @UpdateTimestamp.

Exemplu:

@Entity
@Table(name = "entities")
public class Entity {
  ...

	@CreationTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "create_date")
    private Date createDate;

	@UpdateTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "modify_date")
	private Date modifyDate;
}

Coloanele marcate cu aceste adnotări vor stoca întotdeauna ora corectă când a fost creat obiectul și când a fost modificat ultima dată.

5.2 Adnotare @PrePersist

Dacă aveți nevoie de niște scripturi mai complexe pentru a controla timpul unui obiect, atunci Hibernate are adnotări și pentru acest caz. Ele pot marca metode de clasă, iar Hibernate va apela aceste metode atunci când salvează obiectul în baza de date. Există în total 7 astfel de adnotări:

@PrePersist Apelat înainte ca obiectul să fie salvat în baza de date. (SQL INSERT)
@PostPersist Apelat imediat după ce obiectul este salvat în baza de date. (SQL INSERT)
@PreRemove Apelat înainte de ștergerea unui obiect din baza de date.
@PostRemove Apelat după ce un obiect a fost șters din baza de date.
@PreActualizare Apelat înainte de a actualiza (SQL UPDATE) un obiect din baza de date.
@PostUpdate Apelat după o actualizare (SQL UPDATE) a unui obiect din baza de date.
@PostLoad Apelat după ce obiectul a fost încărcat din baza de date.

Să scriem un exemplu în care spunem unei clase ora corectă pentru a-și crea și actualiza obiectele:

@Entity
@Table(name = "entities")
public class Entity {
  ...

  @Column(name="created_time")
  private Date created;

  @Column(name="updated_time")
  private Date updated;

  @PrePersist
  protected void onCreate() {
    created = new Date();
  }

  @PreUpdate
  protected void onUpdate() {
  updated = new Date();
  }
}

Dacă Hibernate salvează obiectul pentru prima dată, atunci va apela metoda adnotată cu @PrePersist. Dacă actualizează un obiect existent în baza de date, va apela metoda marcată cu adnotarea @PreUpdate.

5.3 Adăugarea EntityListeners-ului nostru

Dacă chiar aveți nevoie, puteți separa metodele pe care Hibernate le apelează de obiectul pe care le apelează. Specificația JPA vă permite să declarați clase de ascultător care vor fi apelate la anumite momente la procesarea obiectelor Entity.

Dacă aveți o mulțime de obiecte Entity similare, atunci puteți muta unele dintre ele în clasa de bază și adăugați un Ascultător care le-ar controla comportamentul. Exemplu:


@MappedSuperclass
public abstract class BaseEntity {
 
    private Timestamp createdOn;
 
    private Timestamp updatedOn;
 
}


@Entity
public class User extends BaseEntity {
 
     @Id
     private Long id;
 
     private String name;
}

Apoi, pentru clasa BaseEntity, puteți crea o clasă de ascultător specială:


public class TimeEntityListener {
 
    public void onPersist(Object entity) {
    	if (entity instanceof BaseEntity) {
        	BaseEntity baseEntity = (BaseEntity) entity;
        	baseEntity.createdOn = now();
    	}
    }
 
    public void onUpdate(Object entity) {
    	if (entity instanceof BaseEntity) {
        	BaseEntity baseEntity = (BaseEntity) entity;
        	baseEntity.updatedOn = now();
    	}
    }
 
    private Timestamp now() {
    	return Timestamp.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)   );
    }
}

Și puteți conecta clasa User și ascultătorul său folosind câteva adnotări:


@Entity
@EntityListeners(class= TimeEntityListener.class)
public class User extends BaseEntity {
 
     @Id
     private Long id;
 
     private String name;
}