Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate @ManyToOne Referenced Class using @NaturalId instead of @Id

I have some Hibernate/JPA annotations (still don't know the difference to be honest) that are allowing me to create an association class. This class is combining two items that are related into one object. I originally was using @JoinTable but realized I needed a lot more meta data with the associations, so had to convert the code over into another object type.

For now I am using @Id to mark the ID column for my objects, and using @NaturalId (mutable = false) for a String uuid.

My association class is using @ManyToOne and creates the table just fine, but when I look into it the table is using the @Id field as the mapping column. I would prefer to have this association class use the @NaturalId uuid for ease of transferring relationship/associations across to other systems.

How can I get the relationship to use the correct identifier?

For reference, my DB's and Java code look like this:

AssociationsTable
----------------------------------------------
| ID | META DATA | ID ASSOC. 1 | ID ASSOC. 2 |
----------------------------------------------
| 1  |  stuff    |    1        |     2       |
----------------------------------------------

Objects
------------------------------
| ID | META DATA | UUID      | 
------------------------------
| 1  |  stuff    |  FOO-123  |
------------------------------
| 2  |  stuff    |  BAR-456  |
------------------------------

Association Class{
  ObjA main;
  ObjA sub;

  @ManyToOne
  getMain()

  @ManyToOne
  getSub()
}

ObjA Class{
  Long id;
  @Id
  @GeneratedValue(generator="increment")
  @GenericGenerator(name="increment", strategy = "increment")
  @XmlElement
  @Column(name = "ID", unique = true, nullable = false)
  getId()

  String uuid;    
  @NaturalId (mutable = false)
  @GeneratedValue(generator = "uuid")
  @GenericGenerator(name = "uuid", strategy = "uuid2")
  @Column(name = "uuid", unique = true)
  getUUID()
}
like image 361
Walls Avatar asked Aug 14 '15 15:08

Walls


1 Answers

You can use the referencedColumnName attribute of @JoinColumn, as mentioned here. So for your example, the mappings should be as follows:

ObjA.java:

package hello;

import org.hibernate.annotations.NaturalId;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class ObjA {
    Long id;
    String uuid;

    public ObjA() {
    }

    public ObjA(String uuid) {
        this.uuid = uuid;
    }

    @Id
    @GeneratedValue
    @Column(name = "obj_a_id", unique = true, nullable = false)
    Long getId() {
        return id;
    }

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

    @NaturalId(mutable = false)
    @Column(name = "uuid", unique = true, nullable = false)
    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
}

Association.java:

package hello;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity
public class Association {
    Long id;
    ObjA main;
    ObjA sub;

    public Association() {
    }

    public Association(ObjA main, ObjA sub) {
        this.main = main;
        this.sub = sub;
    }

    @Id
    @GeneratedValue
    @Column(name = "association_id", unique = true, nullable = false)
    Long getId() {
        return id;
    }

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

    @ManyToOne
    @JoinColumn(name = "main_uuid", referencedColumnName = "uuid", nullable = false)
    public ObjA getMain() {
        return main;
    }

    public void setMain(ObjA main) {
        this.main = main;
    }

    @ManyToOne
    @JoinColumn(name = "sub_uuid", referencedColumnName = "uuid", nullable = false)
    public ObjA getSub() {
        return sub;
    }

    public void setSub(ObjA sub) {
        this.sub = sub;
    }
}

These mappings were successfully tested to store values from the uuid column of the obja table in the main_uuid and sub_uuid columns of the association table. This was tested using org.hibernate.common:hibernate-commons-annotations:4.0.5.Final, org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final, org.hibernate:hibernate-core:4.3.10.Final, and org.hibernate:hibernate-entitymanager:4.3.10.Final against PostgreSQL 9.4.4.

like image 65
heenenee Avatar answered Oct 23 '22 04:10

heenenee