JPA的一對多映射(雙向)關聯


       實體Customer:用戶。

  實體Order:訂單。

  Customer和Order是一對多關系。那么在JPA中,如何表示一對多的雙向關聯呢?

  JPA使用@OneToMany和@ManyToOne來標識一對多的雙向關聯。一的一端(Customer)使用@OneToMany,多端(Order)使用@ManyToOne。

  在JPA規范中,一對多的雙向關系由多端(Order)來維護。就是說多端(Order)為關系維護端,負責關系的增刪改查。一端(Customer)則為關系被維護端,不能維護關系。

  一端(Customer)@OneToMany注釋的mappedBy="customer"屬性表明Customer是關系被維護端。

  多端(Order)使用@ManyToOne和@JoinColumn來注釋屬性CUSTOMER_ID,@ManyToOne表明Order是多端,@JoinColumn設置在Order表中的關聯字段(外鍵)。

     Customer實體類如下:

/**
 *數據庫持久化類
 * @author z
 *
 */
@Table(name="JPA_CUSTOMERS")//主要是映射表名對應的數據庫表名JPA_CUSTOMER默認情況下可以不寫表名與持久化類名相同
@Entity //表明這是一個持久化類
public class Customer {
    
    private Integer id;
    private String lastName;
    private String email;
    private int  age ;
    
    private Date createdTime;
    private Date birth;
    
    /**
     * 單向一對多關系映射
     * 1、添加多的一方的集合屬性
     */
      private Set<Order> orders=new HashSet<>();
    
    /**
     * 定義各數據列必須加在get方法上
     * @return
     */
    //定義主鍵,生成主鍵的策略AUTO自動的根據數據的類型生成主鍵
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Id //定義數據列
//    @Column(name="ID")//定義數據庫的列名如果與字段名一樣可以省略
    
    //使用table生成主鍵
//    @TableGenerator(name="ID_GENERATOR",
//            table="JPA_ID_GENERATORS",
//            pkColumnName="PK_NAME",
//            pkColumnValue="CUSTOMER_ID",
//            valueColumnName="PK_VALUE",
//            allocationSize=100
//            
//            
//            )
//    
//    @GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR")
//    @Id
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    
    @Column(name="LAST_NAME",length=50,nullable=false) //nullable false表示此字段不能為空
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    @Temporal(TemporalType.TIMESTAMP)
    public Date getCreatedTime() {
        return createdTime;
    }
    public void setCreatedTime(Date createdTime) {
        this.createdTime = createdTime;
    }
    @Temporal(TemporalType.DATE)
    public Date getBirth() {
        return birth;
    }
    public void setBirth(Date birth) {
        this.birth = birth;
    }
    
    //映射單向一對多的關聯關系
    //使用@OneToMany 來映射一對多的關聯關系
    //使用@JoinColumn 來映射外鍵列的名稱
    //可以使用@OneToMany的fetch 屬性來修改默認的加載策略
    //可以通過@OneToMany的cascade 屬性來修改默認的刪除策略
    //cascade={CascadeType.REMOVE} 會把主表和從表的數據都刪除
    //mappedBy表明放棄關聯關系維護並且不能在使用
    //注意:若在一的一端@oneToMany 中使用mapperBy屬性,則@oneToMany端就不能在使用@JoinColumn(name="CUSTOMER_ID")屬性
//    @JoinColumn(name="CUSTOMER_ID")
    @OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.REMOVE},mappedBy="customer")
   public Set<Order> getOrders() { 
        return orders;
    }
    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }
    
    //工具方法,不需要映射為數據表的一列
    @Transient
    public String getInfo(){
        return "lastName:"+lastName+",email:"+email;
    }
    @Override
    public String toString() {
        return "Customer [id=" + id + ", lastName=" + lastName + ", email=" + email + ", age=" + age + ", createdTime="
                + createdTime + ", birth=" + birth + "]";
    }
    

}
 
         

 

 

 

多的一端實體類Order如下:

/**
 * 單向多對一
 * 一個訂單可以有多個用戶
 * 一個用戶可以有多個訂單
 * @author z
 *
 */
@Table(name="JPA_ORDERS")
@Entity
public class Order {
    private Integer id;
    private String orderName;
    
    private Customer customer;
    @GeneratedValue//使用默認的主鍵生成方式
    @Id
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
    @Column(name="ORDER_NAME")
    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }
    //映射單向n-1的關聯關系
    //使用@ManyToOne 來映射多對一的關系
    //使用@JoinColumn 來映射外鍵
    //可以使用@ManyToOne的fetch屬性來修改默認的關聯屬性的加載策略
    @JoinColumn(name="CUSTOMER_ID")//外鍵列的列名
    @ManyToOne(fetch=FetchType.LAZY)
    public Customer getCustomer() {
    return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    @Override
    public String toString() {
        return "Order [id=" + id + ", orderName=" + orderName + ", customer=" + customer+ "]";
    }
    

}

簡單的測試類

public class JPATest {
    private EntityManagerFactory entityManagerFactory;
    private EntityManager entityManager;
    private EntityTransaction transaction;
    @Before
    public void init(){
        entityManagerFactory= Persistence.createEntityManagerFactory("jpa-1");
        entityManager=entityManagerFactory.createEntityManager();
        transaction=entityManager.getTransaction();
        transaction.begin();//開啟事務
        
    }
    @After
    public void destroy(){
        transaction.commit();
        entityManager.close();
        entityManagerFactory.close();
    }
    
    //修改
    @Test
    public void testUpdate(){
        Customer customer=entityManager.find(Customer.class, 4);
        customer.getOrders().iterator().next().setOrderName("O-XXX-10");
        
    }
    
     //刪除
    //默認情況下,若刪除1的一端,則會先把關聯的多的一段的外鍵置空,然后刪除一的一端
    ////可以通過@OneToMany的cascade 屬性來修改默認的刪除策略
    @Test
    public void testOneToManyRemove(){
        Customer customer=entityManager.find(Customer.class, 7);
        entityManager.remove(customer);
        
    }
    
    //默認對關聯多的一方使用懶加載的加載策略(延遲加載)
    //可以使用@OneToMany的fetch 屬性來修改默認的加載策略
    //查詢
    @Test
    public void testOneToManyFind(){
        Customer customer=entityManager.find(Customer.class,6);
        System.out.println(customer.getLastName());
        
        System.out.println(customer.getOrders().size());
        
    }
    
    //雙向一對多的關聯關系在執行保存時
    //若先保存多的一端,在保存一的一端,默認情況下,會多出四條update語句
    //若先保存一的一端則會多出2(n)條update語句
    //在進行雙向一對多的關聯關系時,建議使用多的一方來維護關聯關系,而1的一方不維護關聯關系,這樣會有效的減少sql語句
    //注意:若在一的一端@oneToMany 中使用mapperBy屬性,則@oneToMany端就不能在使用@JoinColumn(name="CUSTOMER_ID")屬性//保存
    @Test
    public void testOneToManyPersist(){
        Customer customer=new Customer();
        customer.setAge(16);
        customer.setBirth(new Date());
        customer.setCreatedTime(new Date());
        customer.setEmail("CC@163.com");
        customer.setLastName("AA");
        
        Order order1=new Order();
        order1.setOrderName("o-CC-1");
        
        Order order2=new Order();
        order2.setOrderName("o-CC-2");
        
        //建立關聯關系
        customer.getOrders().add(order1);
        customer.getOrders().add(order2);
        //執行保存操作
        entityManager.persist(customer);
        entityManager.persist(order1);
        entityManager.persist(order2);    
        
    }
    }

源碼地址:https://github.com/wuhongpu/JPA.git

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM