Imagine the following two entities. Element
is simple class containing some data:
@Entity
public class Element {
private String data;
public String getData() { return data; }
public void setData(String data) { this.data = data; }
}
Next class, named VersionedElement
, extends Element
and contains different versions along with current version. Here is my "solution":
@Entity
public class VersionedElement extends Element {
private Set<Element> versions;
private Element currentVersion;
@Override
public String getData() {
return getCurrentVersion().getData();
}
@Override
public void setData(String data) {
getCurrentVersion().setData(data);
}
@OneToMany
public Set<Element> getVersions() {
return versions;
}
public void setVersions(Set<Element> versions) {
this.versions = versions;
}
@ManyToOne
public Element getCurrentVersion() {
return currentVersion;
}
public void setCurrentVersion(Element currentVersion) {
this.currentVersion = currentVersion;
}
}
And I don't like what I've written, something wrong with it, too straightforward approach. First of all, in the latter class currentVersion
isn't limited by and has no relation to versions
. Looks like the code is lacking some helper classes, or abstraction level, or JPA annotation technique, or all above. I need an elegant, worthy of JPA manual solution for this simple case.
Any hints, links or code snippets would be appreciated.
if you want a ready-to-rock hibernate entity versioning solution try hibernate-envers. It will make object versioning/auditing a breeze for you. Check the documentation at http://docs.jboss.org/envers/docs/index.html
cheers and good luck!
Element
can have an integer field version
in the object Element
itself, acting as a running count of rows, and is updated by a sequence. When you want the latest, you simply need to order by this field in descending order and fetch the first result.
@Entity
@NamedQueries({
@NamedQuery(name="GetHistory", query = "FROM Element e WHERE e.id = :id"),
@NamedQuery(name="GetLatest", query = "FROM Element e \
WHERE e.id = :id order by e.version"),
})
public class Element {
private String data;
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "SEQ_ELEMENT_VERSION")
private int version;
private int id;
public String getData() { return data; }
public void setData(String data) { this.data = data; }
}
Your solution would work, but having another table for the VersionedElement would be a performance overhead: VersionedElement would have no usefull data except some foreign key columns.
What I would do is simply add Element latest as field to class Element. Then, in the DAO, I would add some methods which perform queries based on this field:
List<Element> getHistory(Element element)...
Element getLatest(Element element)...
JPA also supports the @Version annotation, but that's used for optimistic concurrency control. It still might be used for tracking version numbers though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With