一對多,多對一關系映射
現實生活中有很多1對多(多對1)的關系模型。比如,一個人可以有0到多套房子,0到多輛汽車;一個父親有0到多個孩子等等。這種關系被稱作1對多關系。反過來,房子與人,汽車與人的關系,以及孩子與父親的關系就是多對一的關系。這里需要注意一點的是,多對一關系的一個前提是:一套確定的房子只能屬於某個確定的人(不能屬於多人);一個確定的孩子也只能屬於某個確定的父親。
下面我們就拿最簡單的父親和孩子的關系來說明1對多(多對1)模型的映射。
關系模型:父親 vs 孩子(Father vs Son)。
關系映射:one-to-many
反過來,
關系模型:孩子 vs 父親(Son vs Father)。
關系映射:many-to-one
很多初學者往往有這樣的疑問,我什么時候需要定義映射關系呢?
答案很簡單:按需求來確定。就是說你需要哪種關系的時候就定義哪種映射,不需要的時候就可以不定義它們的關系映射了。還是以上面的例子來說明。
如果你需要在取得孩子(Son)的時候,同時需要知道該孩子的父親(Father)是誰,你就可以在孩子的實體類里定義孩子跟父親的關系映射: @ManyToOne 。
同樣,如果需要知道某父親的所有孩子,就可以在父親的實體類里定義父親跟孩子的關系映射: @OneToMany 。
1.ManyToOne(多對一)
單向:不產生中間表,但可以用@Joincolumn(name=" ")來指定生成外鍵的名字,外鍵在多的一方表中產生!
2.OneToMany(一對多)
單向:會產生中間表,此時可以用@onetoMany @Joincolumn(name=" ")避免產生中間表,並且指定了外鍵的名字(別看 @joincolumn在一中寫着,但它存在在多的那個表中)
3.OneToMany ,ManyToOne 雙向(
兩個注解一起用的):如果不在 @OneToMany 中加mappedy屬性就會產生中間表,此時通常在 @ManyToOne 的注 解下再添上注解 @Joincolumn(name=" ") 來指定外鍵的名字(說明:多的一方為關系維護端,關系維護端負責外鍵記錄的更新,關系被維護端沒有權利更新 外鍵記錄)!( @OneToMany(mappedBy="一對多中,多中一的屬性") 出現mapby為被維護端|||默認為延遲加載)
用例:
1 @ManyToOne(fetch=FetchType.LAZY) 2 @JoinColumn(name="child_id") 3 private OrderChild orderChild; 4 5 @OneToMany(mappedBy="orderChild",fetch=FetchType.LAZY,cascade={CascadeType.MERGE}) 6 @NotFound(action=NotFoundAction.IGNORE)//代表可以為空,允許為null 7 private List<OrderChildGoods> goodsList;
hibernate中@ManyToOne默認是立即加載,@OneToMany默認是懶加載
但是如果加上了@NotFound之后設置的fetch=FetchType.LAZY是不起作用的,也就是設置@NotFound后變為了立即加載eager
下面舉例詳細說明一下
@ManyToOne
@ManyToOne注解的這端,是多端
1.在注釋@ManyToOne(cascade=CascadeType.REFRESH,optional=true)中將屬性optional設置為true,這可以使得即使外鍵為空時仍可以向表中添加數據。
2.假設Person和Book是一對多的關系,其中Person的成員變量為:
1 private Integer personId; 2 private String name; 3 private Short age; 4 private List<Book> bookList=new ArrayList<Book>();
對應在MySql中表的結構為:Person(personId,name,age),不必有bookList一項,在getBookList上方通過注釋:
1 @OneToMany(mappedBy="person",cascade=CascadeType.ALL) 2 @OrderBy(value="bookId ASC")
與Book關系形成一對多的關系。
Book的成員變量是:
1 private int bookId; 2 private String title; 3 private double price; 4 private Person person;
對應在MySql中表的結構為:Book(bookId,title,price,personId),注意要有Person表的主鍵personId,這樣在插入記錄時才不會產生異常。在getPerson上方有注釋:
1 @ManyToOne(cascade=CascadeType.REFRESH,optional=true) 2 @JoinColumn(name="personId")
與@OneToMany形成呼應。
在EJB3.0 規范中 多對一與一對多的雙向關系, 多對一(就是 @ManyToOne 注解的這端,是多端哦不要搞混了)這端總是雙向關聯端的主題(owner)端, 而一對多端的關聯注解為 @OneToMany(mappedBy=" " ) 其值是:多對一端的屬性
demo:
被動方:其實也就是一方 或者說(OneToMany方)
1 @Entity 2 public class Customer extends AbstractEntity { 3 private String name; 4 5 @OneToMany(mappedBy="customer",cascade=CascadeType.ALL) 6 private Set<Order> orders; 7 public void addOrder(Order order){ 8 if(orders == null){ 9 orders = new HashSet<Order>(); 10 } 11 orders.add(order); 12 } 13 14 public String getName() { 15 return name; 16 } 17 public void setName(String name) { 18 this.name = name; 19 } 20 public Set<Order> getOrders() { 21 return orders; 22 } 23 public void setOrders(Set<Order> orders) { 24 this.orders = orders; 25 } 26 27 }
主動方:1.關系的維護方2.ManyToOne方3.多方
1 @Entity 2 @Table(name="orders") 3 public class Order extends AbstractEntity { 4 private String name; 5 6 @ManyToOne(cascade=CascadeType.ALL) 7 private Customer customer; 8 9 10 public Customer getCustomer() { 11 return customer; 12 } 13 public void setCustomer(Customer customer) { 14 this.customer = customer; 15 } 16 public String getName() { 17 return name; 18 } 19 public void setName(String name) { 20 this.name = name; 21 } 22 }
以上是實體
下面是測試用列哦
1 public void testCRUD() { 2 // 第一種情況: 調用的被動方的Dao 綁定主動方關系,但主動方沒有綁定被動方 3 Customer entity = new Customer(); 4 entity.setName("customer1"); 5 Order order = new Order(); 6 order.setName("order1"); 7 entity.addOrder(order); 8 entity = customerDao.create(entity); // 這種情況下 orders.customer_id == null 9 //控制台的信息 10 //Hibernate: insert into Customer (name, id) values (?, ?) 11 //這里的customer_id 為null 12 //Hibernate: insert into orders (name, customer_id, id) values (?, ?, ?) 13 System.out.println("entity id = " + entity.getId()); 14 System.out.println("order id = "+ order.getId()); 15 System.out.println("1111********************** over"); 16 17 // 第二種情況: 調用的被動方的Dao 綁定主動方關系,並且主動方也綁定被動方 18 entity = new Customer(); 19 entity.setName("customer2"); 20 order = new Order(); 21 order.setName("order2"); 22 entity.addOrder(order); 23 order.setCustomer(entity); //這里進行雙向關聯 24 entity = customerDao.create(entity); 25 // 26 //Hibernate: insert into Customer (name, id) values (?, ?) 27 //這里的customer_id 有值哦 28 //Hibernate: insert into orders (name, customer_id, id) values (?, ?, ?) 29 System.out.println("entity id = " + entity.getId()); 30 System.out.println("order id = "+ order.getId()); 31 System.out.println("2222********************** over"); 32 // 第三種情況: 調用的主動方的Dao 綁定被動方關系,但是被東方不綁定主動方 33 entity = new Customer(); 34 entity.setName("customer3"); 35 order = new Order(); 36 order.setName("order3"); 37 order.setCustomer(entity); //綁定被動方 38 orderDao.create(order); 39 //Hibernate: insert into Customer (name, id) values (?, ?) 40 //Hibernate: insert into orders (name, customer_id, id) values (?, ?, ?) 41 System.out.println("entity id = " + entity.getId()); 42 System.out.println("order id = "+ order.getId()); 43 System.out.println("3333********************** over"); 44 45 // 第四種情況: 調用的主動方的Dao 綁定被動方關系,並且被東方也綁定主動方 46 entity = new Customer(); 47 entity.setName("customer4"); 48 order = new Order(); 49 order.setName("order4"); 50 order.setCustomer(entity); //綁定被動方 51 orderDao.create(order); 52 System.out.println("entity id = " + entity.getId()); 53 System.out.println("order id = "+ order.getId()); 54 System.out.println("4444********************** over"); 55 //Hibernate: insert into Customer (name, id) values (?, ?) 56 //Hibernate: insert into orders (name, customer_id, id) values (?, ?, ?) 57 58 //總結:經測驗二三四種方法結果都是一樣都能持久化到數據庫,並且關系也建立好了 59 // 也就說只要主動方綁定了被動方關系就維護好了 60 } 61 *****************************************做級聯刪除測試************************************************************ 62 public void testCascade(){ 63 64 //1. 做個級聯刪除吧 測試刪除主動方是否刪除關聯方 65 // 這里會級聯刪除主動方的關聯對象,以及該關聯對象(被動方)所關聯的所有主動方都會被級聯刪除 66 orderDao.delete("order_id_1"); 67 //Hibernate: delete from orders where id=? 68 // Hibernate: delete from orders where id=? 69 // Hibernate: delete from orders where id=? 70 // Hibernate: delete from orders where id=? 71 // Hibernate: delete from orders where id=? 72 // Hibernate: delete from Customer where id=? 73 assertNull( orderDao.findById("orderDao")); 74 75 //2. 做個級聯刪除吧 測試刪除被動方是否刪除關聯方 76 //刪除該被動方,以及所關聯的所有主動方(維護關系方or多方)與上面的調用主動方的結果一樣 77 //Hibernate: delete from orders where id=? 78 // Hibernate: delete from orders where id=? 79 // Hibernate: delete from orders where id=? 80 // Hibernate: delete from orders where id=? 81 // Hibernate: delete from orders where id=? 82 // Hibernate: delete from Customer where id=? 83 customerDao.delete("2"); 84 assertNull( customerDao.findById("2")); 85 86 }
參考:http://blog.csdn.net/daryl715/article/details/1886892
http://blog.csdn.net/jackieliulixi/article/details/19043753
http://blog.csdn.net/xiaodaiye/article/details/51118870
http://blog.csdn.net/xiaodaiye/article/details/51118870
