Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA - "versioned" entity, design advice needed

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.

like image 548
andbi Avatar asked Mar 24 '11 22:03

andbi


3 Answers

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!

like image 186
Lucas de Oliveira Avatar answered Sep 25 '22 02:09

Lucas de Oliveira


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; }
}
like image 38
CMR Avatar answered Sep 22 '22 02:09

CMR


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.

like image 40
Ioan Alexandru Cucu Avatar answered Sep 22 '22 02:09

Ioan Alexandru Cucu