Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Envers: Unidirectional OneToMany without additional audit table?

The following database schema:

Employee[EMP_ID (PK), name, salary]

Phone[ID (PK), number_str, OWNER_ID (FK)]

Employee_aud[EMP_ID (PK), REV (PK/FK), REVTYPE, name, salary]

Phone_aud[ID (PK), REV (PK/FK), REVTYPE, number_str]

Employe_phone_aud[REV(PK/FK), OWNER_ID(PK/FK), REVTYPE(PK/FK)]

can be expressed with the following Java Entities:

Employee:

@Entity
@Audited
public class Employee {

    @Id
    @GeneratedValue
    @Column(name = "EMP_ID")
    private long id;

    @Column
    private String name;

    @Column
    private int salary;

    @OneToMany
    @JoinColumn(name = "OWNER_ID", referencedColumnName = "EMP_ID")
    private final List<Phone> phones = new ArrayList<Phone>();

    public Employee(final String name, final int salary) {
        this.name = name;
        this.salary = salary;
    }

    public long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(final int salary) {
        this.salary = salary;
    }

    public void addPhone(final Phone phone) {
        this.phones.add(phone);
    }
}

Phone:

@Entity
@Audited
public class Phone {

    @Id
    @GeneratedValue
    private long id;

    @Column(name = "number_str")
    private String number;

    public Phone(final String number) {
        this.number = number;
    }

    public long getId() {
        return id;
    }

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

    public String getNumber() {
        return number;
    }

    public void setNumber(final String number) {
        this.number = number;
    }
}

As you can see, there is a linking table between the auditing tables, but no linking table between the entity tables. In the Hibernate-Envers Developerguide I found the following text:

When a collection is mapped using these two (@OneToMany+@JoinColumn) annotations, Hibernate doesn't generate a join table. Envers, however, has to do this, so that when you read the revisions in which the related entity has changed, you don't get false results.

This is my interpretation of this text: My Employee Entity may belong to many phone entities. If I e.g add a Phone to a certain Employee then my Employee gets modified and thus an audit entry has to be made. Using the mapping above, this would result into an audit entry for the Phone Entity and not for the Employee. This problem is solved using the linking table (as this table describes the changes within the phone-collection owned by the employee).

Now my 3 questions: - Do I understand the above statement correct or am I missing something special? - If Envers didn't create this linking table, it would also be possible to keep track of these relations by looking at the phone_aud table. Is this true? - Is it possible to configure / extend envers to support this behavior?

Note: I am asking the question just because I want to know whether it is possible to get rid of the extra linking table and to get a better understanding why it is needed.

Thank you!

like image 491
Andreas Aumayr Avatar asked Nov 05 '13 18:11

Andreas Aumayr


1 Answers

  1. yes, you understand the statement from the documentation correctly
  2. yes, but reading the history of changes of "Phone" would give you subsequent objects which are identical (as only the emp_id would change)
  3. no, it's not possible to change this behaviour currently. Unless you e.g. change your mapping to a bi-directional one-to-many relation
like image 109
adamw Avatar answered Oct 03 '22 18:10

adamw