JPA - "version", design consultation required

Imagine the following two objects. Element- a 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; }
}

The next class is named VersionedElement, extends Elementand contains different versions along with the 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 do not like what I wrote, something is wrong with this, too simple an approach. First of all, in the last class is currentVersionnot limited and is not related to versions. It seems that the code does not have any helper classes, an abstraction layer or a JPA annotation technique or all of the above. For this simple case, I need an elegant, decent guide for JPA. Any hints, links or snippets of code would be appreciated.

+5
6
+13

Element version Element, . , .

@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; }
}
+4

, VersionedElement : VersionedElement , .

, last Element. DAO , :

List<Element> getHistory(Element element)...
Element getLatest(Element element)...

JPA @Version, concurrency. .

+2

, @Ioan Alexandru Cucu answer

, - sql - ,

, , , VersionedElement, ,

from
    VersionedElement v
inner join fetch
    v.versions
inner join fetch
    v.currentVersion
where
    v.id = :id

, VersionedElement. , VersionedElement data. , , , , .

@MappedSuperclass
public abstract class AbstractElement {

    private String data;

    public String getData() { return data; }
    public void setData(String data) { this.data = data; }

}

JPA 1.0

. -, , - .

@MappedSuperclass,   , . Element VersionedElement.

, Element

@Entity
public class Element extends AbstractElement {}

v.currentVersion, , AbstractElement, @Embedded, @ManyToOne?

@Embeddable
public class ElementAsEmbeddable extends AbstractElement {}

@Entity
public class VersionedElement {

    private ElementAsEmbeddable currentElement;

    private Set<Element> versions;

    @Embedded
    public ElementAsEmbeddable getCurrentVersion() { return currentVersion; }
    public void setCurrentVersion(ElementAsEmbeddable currentVersion) { this.currentVersion = currentVersion; }

    @OneToMany
    public Set<Element> getVersions() { return versions; }
    public void setVersions(Set<Element> versions) { this.versions = versions; }

}

from
    VersionedElement v
inner join fetch
    v.versions
where
    v.id = :id

currentVersion , AbstractElement

versionedElement.setCurrentVersion((AbstractElement) element);
+2

There is nothing wrong with your solution, but you can use entity listeners to ensure the state of your objects in a more elegant way, I think with @prePersist and @preUpdate listeners. Or, alternatively, go to the list instead of typing.

0
source

You can simply save the link to the last object in a separate table (with one row). Sort of:

@Entity
public class CurrentElement {

    @OneToOne        
    private Element currentVersion;

    public static Element getCurrentVersion(EntityManager em) {
         return em.createQuery("select x from Element x ").getSingleResult().currentVersion;
    }

    public static void setCurrentVersion(EntityManager em, Element newVersion) {
         em.remove(getCurrentVersion(em));
         CurrentElement ce = new CurrentElement();
         ce.currentVersion = newVersion;
         em.persist(ce);
    }
}
-1
source

All Articles