Hibernate基礎之十:一對多關聯的[email protected
一:Group和Users兩個類
假定一個組裡有n多使用者,但是一個使用者只對應一個使用者組。
1.所以Group對於Users是“一對多”的關聯關係@OneToMany
Users對於Group是“多對一”@ManyToOne
2.CRUD時候,希望是能從具體使用者Users查到其對應的Group,反過來也能通過Group查到具體Users,所以是雙向關聯
(所以要用mappedBy去除冗餘資訊)
@Entity @Table(name="t_Group")//指定一個表名 public class Group { private int id; private String name; private Set<Users> users = new HashSet<Users>(); @Id @GeneratedValue//主鍵用自增序列 public int getId() { return id; } @OneToMany(mappedBy="group",cascade=(CascadeType.ALL))//以“多”一方為主導管理,級聯用ALL public Set<Users> getUsers() { return users; }
@Entity @Table(name="t_Users") public class Users { private int id; private String name; private Group group; @Id @GeneratedValue public int getId() { return id; } @ManyToOne(fetch=FetchType.LAZY,cascade=(CascadeType.ALL))//解決1+N,級聯用ALL @JoinColumn(name="groupId")//指定外來鍵名稱,不指定的預設值是group_Id public Group getGroup() { return group; }
二:C增
cascade:級聯,隻影響cud,不影響r
(all全都級聯,persist儲存時級聯,remove刪除時級聯)
如果沒有設定cascade,預設需要save(Group)和save(users),兩個都要存,設定級聯之後,只存一個就行了
級聯依賴於這句:@ManyToOne(cascade=(CascadeType.ALL))//需要依賴於其他的東西時候
設定好正反向之後,多個有級聯關係的物件就一起被儲存了
@Test public void testC() { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Users u1 = new Users(); Users u2 = new Users(); u1.setName("u1"); u2.setName("u2"); //u1和u2的id自增 Group g = new Group(); g.setName("g1"); //g的id自增 g.getUsers().add(u1);//正向 g.getUsers().add(u2); u1.setGroup(g);//反向 u2.setGroup(g);//不然u1和u2中的group資訊為空 session.save(g);//因為設定級聯,所以儲存g時候也把u1和u2存上了。 //不設定級聯的話,還要儲存u1和u2 session.getTransaction().commit(); HibernateUtil.getSessionFactory().close(); }
三:R查
預設會這樣處理(平時管用的思路也是這樣):
1.取“多”的時候,把“一”取出來
2.取“一”時,不取“多”的,用到時候再去取(看user資訊時候一般看組名,看group時候user資訊太多不必看)
fetch管讀取,cascade管增刪改
@OneToMany(mappedBy="group",cascade=(CascadeType.ALL),fetch=FetchType.EAGER)
@OneToMany預設的是LAZY,@ManyToOne預設是EAGER
User u = (User)s.get(User.class,1);
//取user時候,把group也取出來,
Users u = (Users)session.get(Users.class,11);//取id為11號的u
//hibernate產生的語句裡也把group拿出來了:group1_.id as id0_0_,和group1_.name as name0_0_
Hibernate:
select
users0_.id as id1_1_,
users0_.groupId as groupId1_1_,
users0_.name as name1_1_,
group1_.id as id0_0_,
group1_.name as name0_0_
from
t_Users users0_
left outer join
t_Group group1_
on users0_.groupId=group1_.id
where
users0_.id=?
只取出Group的話,不會去查詢裡邊的user
//只取出Group的話,不會去查詢裡邊的user
Group group = (Group)session.get(Group.class,11);
Hibernate:
select
group0_.id as id0_0_,
group0_.name as name0_0_
from
t_Group group0_
where
group0_.id=?
四:U更新
注意:fetch影響兩者讀取順序(兩邊都設成EAGER要多取出一次),反正都要取,具體再試@OneToMany,@ManyToOne都寫cascade=(CascadeType.ALL)
update時候自動關聯更新
//因為cascade=(CascadeType.ALL),所以自動關聯更新
Users u = (Users)session.load(Users.class,11);//取id為11號的u
u.setName("u250");
u.getGroup().setName("gp01");
五:D刪
刪多:實測只刪掉目的專案,不關聯其他
先load(就是select)一下,確認有之後,再刪
沒有遇到:不能直接s.delete(u),因為u和group有級聯,group和所有users都有級聯,一下就夠給刪掉了的情況
不過嚴謹起見,還是設定一個u.setGroup(null);比較好
Users u1 = new Users();
u1.setId(18);
u1.setGroup(null);//嚴謹起見,應該先讓倆表脫離關聯
session.delete(u1);
HQL對應的語句(作用是一樣的):s.createQuery("delete from User u where u.id = 1").executeUpdate();//User是類名
刪一:如果有子專案,報錯不讓刪除
Group g = (Group)s.load(Group.class,1);s.delete(g);
Hibernate:
delete
from
t_Group
where
id=?
22:56:20,691 WARN SqlExceptionHelper:143 - SQL Error: 2292, SQLState: 23000
22:56:20,692 ERROR SqlExceptionHelper:144 - ORA-02292: 違反完整約束條件 (SCOTT.FK9F52DA5D4E678049) - 已找到子記錄