简体   繁体   中英

Composite table with Hibernate Envers

I have an application with a composite table holding one extra column. It all works fine, until we add Hibernate Envers (@Audited).

org.hibernate.MappingException: Unable to read the mapped by attribute for responseDomainCodes in no.pack.response.ResponseDomainCode

I am happy to provide more detailed information if necessary, however, at this time I am not sure what would be relevant.

The tables look like this, and is a pretty standard composite key table, with one extra column.

Database schema

+-----------+---------+
|   CODE    |  TYPE   |
+-----------+---------+
| category  | VARCHAR |
| code      | VARCHAR |
+-----------+---------+
            |
            |
+----------------------+---------+
| RESPONSE_DOMAIN_CODE |  TYPE   |
+----------------------+---------+
| response_domain_id   | KEY     |
| code_id              | KEY     |
| rank                 | VARCHAR |
+----------------------+---------+
            |
            |
+--------------------+------+
|  RESPONSE_DOMAIN   | TYPE |
+--------------------+------+
| response_domain_id | PK   |
| response_kind_id   | FK   |
+--------------------+------+

ResponseDomain.java

@Entity
@Table(name = "responseDomain")
public class ResponseDomain implements Serializable {

    @Id
    @Column(name = "responseDomain_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

   @ManyToOne
   @JoinColumn(name = "respons_kind_id")
   private ResponseKind responseKind;

   @OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.responseDomain",  cascade = CascadeType.ALL)
    private Set<ResponseDomainCode> responseDomainCodes = new HashSet<>();

 //Omitted rest.
}

Code.java

@Entity
@Table(name = "code")
public class Code implements Serializable {

    @Id
    @Column(name = "code_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String category;

    private  String code;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.code", cascade = CascadeType.ALL)
    private Set<ResponseDomainCode> responseDomainCodes = new HashSet<>();

    //Omitted rest
}

ResponseDomainCode.java

@Entity
@Table(name = "responseDomain_code")
@AssociationOverrides(value = {
        @AssociationOverride(name = "pk.responseDomain",
                joinColumns = @JoinColumn(name = "responseDomain_id")),
        @AssociationOverride(name = "pk.code",
                joinColumns = @JoinColumn(name = "code_id"))
})
public class ResponseDomainCode implements Serializable {

    @EmbeddedId
    private ResponseDomainCodeId pk = new ResponseDomainCodeId();

    @Column(name = "rank")
    private String rank;

    public ResponseDomainCodeId getPk() {
        return pk;
    }

    public void setPk(ResponseDomainCodeId pk) {
        this.pk = pk;
    }

    public String getRank() {
        return rank;
    }

    public void setRank(String rank) {
        this.rank = rank;
    }

    @Transient
    public ResponseDomain getResponseDomain() {
        return getPk().getResponseDomain();
    }

    public void setResponseDomain(ResponseDomain responseDomain) {
        this.getPk().setResponseDomain(responseDomain);
    }

    @Transient
    public Code getCode() {
        return getPk().getCode();
    }

    public void setCode(Code code) {
        this.getPk().setCode(code);
    }

    //Omitted rest
}

ResponseDomainCodeId.java

@Embeddable
public class ResponseDomainCodeId implements Serializable {

    @ManyToOne
    private ResponseDomain responseDomain;

    @ManyToOne
    private Code code;

    public ResponseDomainCodeId() {
    }

    public ResponseDomain getResponseDomain() {
        return responseDomain;
    }

    public void setResponseDomain(ResponseDomain responseDomain) {
        this.responseDomain = responseDomain;
    }

    public Code getCode() {
        return code;
    }

    public void setCode(Code code) {
        this.code = code;
    }

    //Omitted rest
}

With the help of @adamw I managed to solve this, by changing my mapping.

Instead of using a composite key, a table with its own unique ID was generated.

+----------------------+------------+
| RESPONSE_DOMAIN_CODE |    TYPE    |
+----------------------+------------+
| id                   | PK(BIGINT) |
| response_domain_id   | BIGINT     |
| code_id              | BIGINT     |
| rank                 | VARCHAR    |
+----------------------+------------+

Now instead of using @Embeddable and @EmbeddedId I have a @ManyToOne and @OneToMany annotation on either side, and query based on ResponseDomain.

This enable full version audit control using Hibernate Envers also in relations like this.

I hope this will be helpful for someone at some point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM