1. 程式人生 > >hibernate多對多對映拆成2個一對多對映(註解)

hibernate多對多對映拆成2個一對多對映(註解)

hibernate的many to many確實很是方便我們處理實體和集合間的關係,並可以通過級聯的方法處理集合,但有的時候many to many不能滿足我們的需要,比如 使用者<--->選課,典型的多對多關係,一般情況下,會生成

course_user(course_id,user_id);

但使用者選課的時候最好加入稽核功能,所以我們希望在中間自動生成的表中加入一個boolean欄位,類似這種結構:

course_user(course_id,user_id,accessable);

這個時候我們可以把many to many拆分成2個many to one ,自己手動添加個中間表,這樣擴充套件就好很多了。

程式碼如下:

@Embeddable
public class CourseUserPK implements Serializable{
    private static final long serialVersionUID = 1L;
    private Course course;
    private User user;

    @ManyToOne
    @JoinColumn(name = "course_id", nullable = false)
    public Course getCourse() {
        return course;
    }

    public void setCourse(Course course) {
        this.course = course;
    }
    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public boolean equals(Object object) {
        if (this == object)
            return true;
        if (!(object instanceof CourseUserPK))
            return false;
        final CourseUserPK other = (CourseUserPK) object;
        if (this.course != null && other.getCourse() != null) {
            if(course.getId() == other.course.getId()) {
                if(user!=null&&other.getUser()!=null&&user.getId()==other.getUser().getId()) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return true;
            }
        } else
            return false;
    }

    public int hashCode() {
        return super.hashCode()+
                (course!=null?course.hashCode():0)+
                (user!=null?user.hashCode():0);
    }
}

@Entity
@IdClass(CourseUserPK.class)
public class CourseTeacher {

    private Course course;
    private User user;
    private Boolean accessable;//true user is in course, otherwise not
   
    public CourseTeacher(Course course, User user, Boolean accessable) {
        this.course = course;
        this.user = user;
        this.accessable = accessable;
    }
    @Id
    public Course getCourse() {
        return course;
    }
    public void setCourse(Course course) {
        this.course = course;
    }
    @Id
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    public Boolean getAccessable() {
        return accessable;
    }
    public void setAccessable(Boolean accessable) {
        this.accessable = accessable;
    }
}

@Entity
@IdClass(CourseUserPK.class)
public class CourseStudent {

    private Course course;
    private User user;
    private Boolean accessable;//true user is in course, otherwise not
   
   
    public CourseStudent(Course course, User user, Boolean accessable) {
        this.course = course;
        this.user = user;
        this.accessable = accessable;
    }
    @Id
    public Course getCourse() {
        return course;
    }
    public void setCourse(Course course) {
        this.course = course;
    }
    @Id
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    public Boolean getAccessable() {
        return accessable;
    }
    public void setAccessable(Boolean accessable) {
        this.accessable = accessable;
    }
}

@Entity
public class Course extends BaseEntity {
    private static final long serialVersionUID = 8768227695335084711L;
    private Set<CourseTeacher> teachers;
    private Set<CourseStudent> students;
   
    @OneToMany(mappedBy="course",cascade=CascadeType.ALL)
    public Set<CourseTeacher> getTeachers() {
        return teachers;
    }
    public void setTeachers(Set<CourseTeacher> teachers) {
        this.teachers = teachers;
    }
    @OneToMany(mappedBy="course")
    public Set<CourseStudent> getStudents() {
        return students;
    }
    public void setStudents(Set<CourseStudent> students) {
        this.students = students;
    }
}

image

image

Hibernate可以通過*.hbm.xml配置檔案能很好地把多對多關係拆分成兩個一對多的關係,但Hibernate Annotation的文件中沒有說到這個點上來。下面通過例項說明用註解來實現多對多拆分成兩個一對多。

下面以商品Product和訂單Order之間的多對多關係來說明。

      Product的屬性包括:

  • id
  • name
  • price

Order的屬性包括:

  • id
  • date(下訂單的時間)
為什麼要把多對多關係拆分成兩個一對多?

因為多對多關係不能儲存兩個實體之間共有的屬性。比如,如何記錄訂單A中購買的商品B的數量呢?如果以多對多對映就不能實現了。

中間實體----用來記錄兩個多對多實體之間共有關係

在Product和Order之間的關係中,可以用一個OrderItem實體來表示兩者多對多中的眾多關係中的一個關係。即Product與OrderItem,Order與OrderItem之間的關係為一對多的關係。

OrderItem的屬性包括:

  • product(假如當前記錄的是商品C)
  • order(假如當前記錄的是訂單D)
  • quantity(這裡記錄的是訂單D中商品C的數量)
例項程式碼(省略了類包引用):
複合主鍵類:
@Embeddable
public class OrderItemPK implements Serializable{
    private Product product;
    private Order order;

    @ManyToOne
    @JoinColumn(name="product_id",referencedColumnName="id")
    public Product getProduct(){
        return product;
    }
    public void setProduct(Product product){
        this.product=product;
    }

    @ManyToOne
    @JoinColumn(name="order_id",referencedColumnName="id")
    public Order getOrder(){
        return order;
    }
    public void setOrder(Order order){
        this.order=order;
    }
    public boolean equals(Object object){...}
    public int hashCode(){...}
}
OrderItem類:
@Entity
@org.hibernate.annotation.Entity(dynamicInsert=true,dynamicUpdate=true)
@Table(name="order_item")
@IdClass(OrderItemPK.class)
public class OrderItem implements Serializable{
    
    private Product product;
    private Order order;
    private int quantity;

    @Id
    public Product getProduct(){
        return product;
    }
    public void setProduct(Product product){
        this.product=product;
    }
    @Id
    public Order getOrder(){
        return order;
    }
    public void setOrder(Order order){
        this.order=order;
    }

    @Column(name="quantity")
    public int getQuantity(){
        return quantity;
    }
    public void setQuantity(int quantity){
        this.quantity=quantity;
    }
}
Product類:
@Entity
@org.hibernate.annotation.Entity(dynamicInsert=true,dynamicUpdate=true)
@Table(name="product")
public class Product implements Serializable{
    private int id;
    private String name;
    private double price;
    private Set<OrderItem> orderItems;

    @Id
    @GenericGenerator(name="g_id",strategy="increment")
    @GeneratedValue(generator="g_id")
    public int getId(){
         return id;
    }
    public void setId(int id){
         this.id=id;
    }
    public String getName(){
         return name;
    }
    public void setName(String name){
         this.name=name;
    }
    public double getPrice(){
         return price;
    }
    public void setPrice(double price){
         this.price=price;
    }
    
    @OneToMany(mappedBy="product")
    public Set<OrderItem> getOrderItems(){
         return orderItems;
    }
    public void setOrderItems(Set<OrderItem> orderItems){
         this.orderItems=orderItems;
    }
}
Order類:
@Entity
@org.hibernate.annotation.Entity(dynamicInsert=true,dynamicUpdate=true)
@Table(name="tbl_order")
public class Order implements Serializable{
    private int id;
    private Calendar date;
    private Set<OrderItem> orderItems;

    @Id
    @GenericGenerator(name="g_id",strategy="increment")
    @GeneratedValue(generator="g_id")
    public int getId(){
        return id;
    }
    public void setId(int id){
        this.id=id;
    }
    public Calendar getDate(){
        return date;
    }
    public void setDate(Calendar date){
        this.date=date;
    }

    @OneToMany(mappedBy="order")
    public Set<OrderItem> getOrderItems(){
        return orderItems;
    }
    public void setOrderItems(Set<OrderItem> orderItems){
        this.orderItems=orderItems;
    }
}