Reputation: 1460
I have a scenario where I have 2 labels that need to be configured. The names of the labels are 'Out Date' and 'In Date'. I only have one field in the database called 'Date'. Whether it is 'Out' or 'In' is decided at the runtime by the value of an Enum 'Scenario'. However, I need to actually show the user Out Date&In Date so that he can select 1 or both of them. I heard that calculated field concept it JPA will assist in this. Is this true or is there some other way that I can achieve this. Below is some sample code.
Date
@Override
@Convert("DateTimeConverter")
@Column(name = "DATE")
public DateTime getDate() {
return date;
}
Scenario
@Override
@Convert("EnumConverter")
@Column(name = "SCENARIO")
public Scenario getScenario() {
return scenario;
}
Scenario is any enum with the values OUT(1),IN(2)
Upvotes: 1
Views: 618
Reputation: 1967
To compute properties within JPA entities, you can use JPA callbacks.
See this Hibernate JPA Callbacks documentation. (Note: JPA callbacks are not specific to hibernate, it's part of latest JPA 2.1 specification). And also this OpenJpa JPA Calbacks one.
Following entity life-cycle categories have a Pre and Post event which can be intercepted by the entity manager to invoke methods:
So let's say you want to compute a complexLabel label from two persisted entity fields label1 and label2 in an entity titled MyEntity:
@Entity
public class MyEntity {
private String label1;
private String label2;
@Transient
private String complexLabel;
@PostLoad
@PostUpdate // See EDIT
// ...
public void computeComplexLabel(){
complexLabel = label1 + "::" + label2;
}
}
As @Dawid wrote, you have to annotate complexLabel with @Transient in order to make them ignored by persistence. If you don't do this, persistence fails because there is no such column in MyEntity corresponding table.
With @PostLoad annotation, computeComplexLabel() method is called by entity manager just after the loading of any instance of MyEntity from persistence. Thus, @PostLoad annotated method is best suited to put your post loading entity properties enhancement code.
Bellow is an extract from JPA 2.1 specification about PostLoad:
The PostLoad method for an entity is invoked after the entity has been loaded into the current persistence context from the database or after the refresh operation has been applied to it. The PostLoad method is invoked before a query result is returned or accessed or before an association is traversed.
EDIT
As pointed out by @Dawid, you could also use @PostUpdate in case you want to compute this transient field just after the entity update, and use other callbacks when needed.
Upvotes: 1
Reputation: 2810
There are no calculated properties in JPA.
You can use @Transient
annotation to create properties that are not persisted but calculated based on other fields:
@Transient
public DateTime getInDate() {
if (scenario == Scenario.IN) {
return date;
}
return null;
}
@Transient
public DateTime getOutDate() {
if (scenario == Scenario.OUT) {
return date;
}
return null;
}
Alternatively, if you are using Hibernate you can use proprietary annotation @Formula
:
@Formula("case when SCENARIO = 2 then DATE else NULL end")
@Convert("DateTimeConverter")
private DateTime inDate;
@Formula("case when SCENARIO = 1 then DATE else NULL end")
@Convert("DateTimeConverter")
private DateTime outDate;
I prefer the first option because:
case when
is SQL 92 compatible so it does not apply hereThe only problem I can is is that in simplest approach is that we abandon encapsulation by exposing to clients internals of the entity (scenario
and date
properties). But you can always hide these properties with accessor protected
, JPA will still handle that.
Upvotes: 2