Hibernate的关联映射——双向1-N关联

时间:2023-12-30 22:14:08

Hibernate的关联映射——双向1-N关联

  对于1-N的关联,Hibernate推荐使用双向关联,而且不要让1的一端控制关联关系,而是用N的一端控制关联关系。双线的1-N关联和N-1关联是两种相同的情形,两端都需要增加对关联属性的访问,N的一端增加引用到关联实体的属性,1的一端增加集合属性,集合的元素为关联实体。

  Hibernate对双向的1-N关联同样提供了有连接表和无连接表的两种关联映射策略。

1.无连接表的双向1-N关联  

  无连接表的双向1-N关联,N的一端需要增加@ManyToOne注解来修饰代表关联实体的属性,而1的一端则需要使用@OneToMany注解来修饰代表关联实体的属性。

  底层数据库为了记录这种1-N关联关系,只需要在N的一端的数据表里添加一个外键列即可,因此应该在使用@ManyToOne注解的同时,使用@JoinColumn来映射外键列。

  对于双向的1-N关联映射,通常不应该允许1的一端控制关联关系,而应该由N的一端控制关联关系,因此应该在使用@OneToMany时指定mappedBy属性——一旦为@OneToMany、@ManyToMany指定了该属性,则表明当前实体不能控制关联关系。当@OneToMany、@ManyToMany、@OneToOne所在的当前实体放弃控制关联关系之后,Hibernate就不会允许使用@JoinColumn或@JoinTable修饰代表关联实体的属性了。

(1)双向1-N中1的一端的代码示例

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="person_info")
public class Person {
    @Id    @Column(name="p_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    @Column(name="p_name")
    private String name;
    @Column(name="p_age")
    private Integer age;
    @OneToMany(targetEntity=Address.class,mappedBy="person")
    private Set<Address> addresses = new HashSet<>();
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Set<Address> getAddresses() {
        return addresses;
    }
    public void setAddresses(Set<Address> addresses) {
        this.addresses = addresses;
    }
}

(2)双向1-N中N的一端的代码示例

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

@Entity
@Table(name="address_info")
public class Address {
    @Id    @Column(name="address_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    @Column(name="address_name")
    private String name;
    @ManyToOne(targetEntity=Person.class)
    @JoinColumn(
            name="p_id",
            referencedColumnName="p_id",
            nullable=false
            )
    private Person person;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Person getPerson() {
        return person;
    }
    public void setPerson(Person person) {
        this.person = person;
    }
}

(3)测试例子

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.mytest.test1.HibernateUtil;

public class Test {
    public static void main(String[] args) {
        Session session = HibernateUtil.currentSession();
        Transaction tx = session.beginTransaction();
        //创建一个瞬态的Person对象
        Person p = new Person();
        //设置Person的属性
        p.setName("liujiang");
        p.setAge(24);
        //持久化Person对象——插入主表记录
        session.save(p);
        //创建一个瞬态的Address对象
        Address a1 = new Address("A");
        //设置Person和Address之间的关联关系
        a1.setPerson(p);
        //持久化Address对象——插入从表记录
        session.persist(a1);
        //再创建一个瞬态的Address对象
        Address a2 = new Address("B");
        //设置Person和Address之间的关联关系
        a2.setPerson(p);
        //持久化Address对象——插入从表记录
        session.persist(a2);
        tx.commit();
        HibernateUtil.closeSession();
    }
}

2.有连接表的双向1-N关联