History, Diff and Reverses of Saved Objects

In a Spring MVC / Spring Data project, I need to implement a mechanism to track history, detect differences, and revert changes to an entity object.

Let's say I have an entity with relationships with others, such as:

@Entity
public Class ModelA{
    @OneToOne(cascade = CascadeType.ALL)
    private ModelB modelB;

    @OneToOne(cascade = CascadeType.ALL)
    private ModelC modelC;
}

I want to have a list of changes, the ability to compare and return them. I know that with Ruby there are libs that provide this kind of functionality, but I don't know if such a thing exists in Java.

Spring has a historiography API and Hibernate Envers has been included in Core functionality, although I still cannot find a simple example or some recommendations for its implementation.

If it concerns the used PostgreSQL and Oracle 11g database, but I want to keep it independent of the database.

+4
3

, , , Memento pattern , .

Spring Data (.. ), . (, AspectJ) DAO (, , ). , , CRUD (, , dao/repository, , ), "" , , .

, , , .

0

Enver Auditions .

+2

One very interesting approach is given by Christian Bauer (Hibernate committer and author of Hibernate in Action and Java Persistence with Hibernate) in this article .

You create the HISTORY table:

create table ITEM (
    ITEM_ID    NUMBER(19) NOT NULL,
    DESC       VARCHAR(255) NOT NULL,
    PRICE      NUMBER(19,2) NOT NULL,
    PRIMARY KEY(ITEM_ID)
)

create table ITEM_HISTORY (
    ITEM_ID    NUMBER(19) NOT NULL,
    DESC       VARCHAR(255) NOT NULL,
    PRICE      NUMBER(19,2) NOT NULL,
    VERSION    NUMBER(10) NOT NULL,
    PRIMARY KEY(ITEM_ID, VERSION)
)

Then, instead, you snap objects to the view:

create or replace view ITEM_VERSIONED (ITEM_ID, VERSION, DESC, PRICE) as
    select I.ITEM_ID as ITEM_ID,
        (select max(IH.VERSION)
            from ITEM_HISTORY HI
            where HI.ITEM_ID = I.ITEM_ID) as VERSION,
        I.DESC as DESC,
        I.PRICE as PRICE
    from   ITEM I

and DML statements are allowed by INSTEAD OF TRIGGERS, which are supported by PostgreSQL and Oracle:

create or replace trigger ITEM_INSERT
    instead of insert on ITEM_VERSIONED begin

    insert into ITEM(ITEM_ID, DESC, PRICE)
           values (:n.ITEM_ID, :n.DESC, :n.PRICE);

    insert into ITEM_HISTORY(ITEM_ID, DESC, PRICE, VERSION)
           values (:n.ITEM_ID, :n.DESC, :n.PRICE, :n.VERSION);
end;

create or replace trigger ITEM_UPDATE
    instead of update on ITEM_VERSIONED begin

    update ITEM set
            DESC = :n.DESC,
            PRICE = :n.PRICE,
           where
            ITEM_ID = :n.ITEM_ID;

    insert into ITEM_HISTORY(ITEM_ID, DESC, PRICE, VERSION)
           values (:n.ITEM_ID, :n.DESC, :n.PRICE, :n.VERSION);
end;

This will work even for other applications that cannot use Hibernate, but they work with the same database.

+1
source

All Articles