使用persistance.ManyToMany 產出DB關聯表轉換成composite key的作法

  • 777
  • 0

使用persistance.ManyToMany 產出composite key的作法

參考網址

The best way to use the @ManyToMany annotation with JPA and Hibernate

 

情境 :

原本公司內技術組組長寫好的 entity ,

是使用 @ManyToMany 的方式產生兩張table之間的關聯表,

但因為新的需求,必須在自動產生的表中加一個欄位 ( isMain那個欄位)

修改前 修改後

 

原始情況 : 

Skill.java & User.java 兩隻檔案,

並且使用hibernate在db產生 at_Skill , at_User , at_Skill_User 三個table

其中 at_Skill_User 的結構如下

Skill.java 裡面的部分code 為

@ManyToMany
@JoinTable(name = "at_Skill_User", indexes = { @Index(name = "idx_skills_id", columnList = "skills_id"),
@Index(name = "idx_users_id", columnList = "users_id") })
private Set<User> users = new HashSet<>();
User.java 裡面的部分code 為   

@ManyToMany(mappedBy = "users")
private Set<Skill> skills = new HashSet<>();

 

修改後 : 

會有四隻檔案,分別為

Skill.java 、 User.java 、 SkillUser.java 、 SkillUserId.java

Skill.java 把原本的code 改為

@OneToMany(mappedBy = "skills", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<SkillUser> skillUser = new HashSet<>();
User.java 把原本的code 改為   

@OneToMany(mappedBy = "users", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<SkillUser> skillUser = new HashSet<>();
SkillUser.java

@Entity
@Table(name = "at_Skill_User", indexes = { @Index(name = "idx_skills_id", columnList = "skills_Id"),
@Index(name = "idx_users_id", columnList = "users_Id") })
public class SkillUser implements Serializable{

    private static final long serialVersionUID = -8189271280419140508L;

    @EmbeddedId
    private SkillUserId id;   

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("skillId")  //這邊要對應到 SkillUserId class 裡面的變數名稱
    private Skill skills;   //hibernate 會用這個名稱在table中產生一個 skills_id 作為 FK

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("userId")  //這邊要對應到 SkillUserId class 裡面的變數名稱
     private User users;  //hibernate 會用這個名稱在table中產生一個 users_id 作為 FK

    @Column(name = "isMain")
    private boolean isMain;

    private SkillUser(){}

    public SkillUser(Skill skill, User user){
        this.skills = skill;
        this.users = user;
        this.id = new SkillUserId(skill.getId(),user.getId());
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass())
                   return false;
        SkillUser that = (SkillUser) o;
        return Objects.equals(skills, that.skills) &&
               Objects.equals(users, that.users);
    }

    @Override
    public int hashCode() {
        return Objects.hash(skills, users);
    }

...(一些setter and getter)
}

 

SkillUserId.java

@Embeddable
public class SkillUserId implements Serializable {

    @Column(name = "skills_id") //hibernate產生的table 會用這個名稱產生一個欄位當成PK
    private Integer skillId;

    @Column(name = "users_id")  //hibernate產生的table 會用這個名稱產生一個欄位當成PK
    private Integer userId;

    private SkillUserId() {}

    public SkillUserId(Integer skillId, Integer userId) {
        this.skillId = skillId;
        this.userId = userId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass())
            return false;
        SkillUserId that = (SkillUserId) o;
        return Objects.equals(skillId, that.skillId) &&
               Objects.equals(userId, that.userId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(skillId, userId);
    }
...(一些setter and getter)
}

 

其中如果hibernate產出的 PK 與 FK 欄位名稱不同的話,會變成兩個欄位,一個欄位為PK,另一個為FK
(我在這一步卡超久)

 

 

 

 

感謝,看到這邊,如果有什麼地方寫錯歡迎指出

By Carl