實體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