1
votes

In this scenario :

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.envers.Audited;

@Entity
@Audited
public class TestEntity implements Serializable {

    @Id
    private Long id;

    @ElementCollection
    private List<String> strings = new ArrayList<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public List<String> getStrings() {
        return strings;
    }

    public void setStrings(List<String> strings) {
        this.strings = strings;
    }
}

Hibernate creates two tables as expected:

CREATE TABLE testentity ( id bigint(20) NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

and

CREATE TABLE testentity_strings ( TestEntity_id bigint(20) NOT NULL, strings varchar(255) DEFAULT NULL, KEY FK6gvnp6uhj6p14qb8jr7w4a4sc (TestEntity_id), CONSTRAINT FK6gvnp6uhj6p14qb8jr7w4a4sc FOREIGN KEY (TestEntity_id) REFERENCES testentity (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Envers also creates two tables :

CREATE TABLE testentity_aud ( id bigint(20) NOT NULL, revision int(11) NOT NULL, action tinyint(4) DEFAULT NULL, PRIMARY KEY (id,revision), KEY FKtoml4ns3581arnt5f7i1srxai (revision), CONSTRAINT FKtoml4ns3581arnt5f7i1srxai FOREIGN KEY (revision) REFERENCES revinfo (REV) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

and

CREATE TABLE testentity_strings_aud ( revision int(11) NOT NULL, TestEntity_id bigint(20) NOT NULL, strings varchar(255) NOT NULL, action tinyint(4) DEFAULT NULL, PRIMARY KEY (revision,TestEntity_id,strings), CONSTRAINT FKadlc041c3dxra6fmfxsku0fuh FOREIGN KEY (revision) REFERENCES revinfo (REV) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

The problem is with the second audit table (testentity_strings). It sets a constraint (NOT NULL) on column 'strings' even though in the main table strings allows null.

My business requirement is to allow null strings. How can I override this behavior in envers?

2

2 Answers

0
votes

The short answer is you can't.

Envers does not treat an element-collection in the same way which ORM does. Instead Envers constructs an entirely separate entity mapping for that element-collection and supplies said mapping to ORM via HBM.

There are a couples reasons we do this but the main reason is that it allows users to configure a mapping such that the element-collection might be audited where-as the remainder of the owning entity is not. ANd because the mapping we supply is an entity-mapping here for the collection, HBM mandates that we must provide ORM with a primary key configuration for it.

We cannot possibly exclude the string-value from the primary key from Envers perspective because you will have multiple values in the collection associated with the same revision number, so some value must differentiate the different rows in the table accordingly.

That said, the only workaround I can see is to use a @OneToMany and wrap your string in an actual entity maping with a generated-id rather than an @ElementCollection if the values need to be audited.

If you decide the values aren't worth auditing, then you can place @NotAudited on the element-collection to also bypass the problem.

0
votes

Nanos- Would it be possible to use the order-column (if provided) as the primary-key instead of the element-value as this is a source point for my project as well. Thanks