1. 程式人生 > >Hibernate基礎之十:一對多關聯的[email protected

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) - 已找到子記錄