导航

Hibernate一对多OnetoMany

Posted on 2017-05-06 14:39  曙光城邦  阅读(1537)  评论(0编辑  收藏  举报
 ------------------------Hibernate一对多OnetoMany
要点:
配置在一端。
1.如果是单向关联,即只在一端配置OneToMany,多端不配置ManyToOne。则会创建一张关系表。
2.如果在单向关联的OneToMany上加上@JoinColumn,则会在多端增加一个外键维护关系,而不单独创建关系表。
3.可以配置级联操作 @OneToMany(cascade=CascadeType.ALL),保存一端的时候保存多端
4.如果是双向关联,即在一端配置OneToMany,多端配置ManyToOne,则在多端增加外键字段维护关系,
并且要使用mappedBy或者是inverse确保只有一端维护关系


2.单向关联
@Entity
public class User {

	@Id
	@GeneratedValue
	private long id;
	
	@Column(name="name")
	private String name;
	
	@OneToMany(cascade=CascadeType.ALL)
	@JoinColumn
	private Set<Role> roles = new HashSet<Role>();
	
}

@Entity
public class Role {
	@Id
	@GeneratedValue
	private long id;
	@Column
	private String name;
}

执行:
        User user = new User();
        user.setName("zhangsan");
        
        Role r1= new Role();
        r1.setName("ADMIN");
        Role r2= new Role();
        r2.setName("EDITOR");
        
        user.getRoles().add(r1);
        user.getRoles().add(r2);
        
        session.save(user);


结果:
Hibernate: 
    insert 
    into
        User
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, id) 
    values
        (?, ?)
Hibernate: 
    update
        Role 
    set
        roles_id=? 
    where
        id=?
Hibernate: 
    update
        Role 
    set
        roles_id=? 
    where
        id=?
保存user后保存两个role 然后更新外键。多两条更新语句。


执行:保存user后删除一个role对象。        
		User user = new User();
        user.setName("zhangsan");
        
        Role r1= new Role();
        r1.setName("ADMIN");
        Role r2= new Role();
        r2.setName("EDITOR");
        
        user.getRoles().add(r1);
        user.getRoles().add(r2);
        
        session.save(user);
        user.getRoles().remove(r1);
结果:
Hibernate: 
    insert 
    into
        User
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, id) 
    values
        (?, ?)
Hibernate: 
    update
        Role 
    set
        roles_id=? 
    where
        id=?

保存user后保存两个role,然后更新被删除role的外键为Null。此时并没有删除role这个数据。
只需要增加orphanRemoval=true,则会删除已经没有关联关系的子实体
@Entity
public class User {

	@Id
	@GeneratedValue
	private long id;
	
	@Column(name="name")
	private String name;
	
	@OneToMany(cascade=CascadeType.ALL,orphanRemoval=true)
	@JoinColumn
	private Set<Role> roles = new HashSet<Role>();
}

结果:
Hibernate: 
    insert 
    into
        User
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, id) 
    values
        (?, ?)
Hibernate: 
    update
        Role 
    set
        roles_id=? 
    where
        id=?
Hibernate: 
    delete 
    from
        Role 
    where
        id=?
		
将移除的子实体更新外键为null,然后执行删除,效率一般。



4.双向关联
要点:关系必须双向都设置,业务代码中关系也必须双向设置
mappedBy指向多端实体里的一端变量名
inverse和mappedBy是同一个东西,只是inverse是用于xml配置,而mappedBy则是用于注解中。 
只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性,ManyToOne不存在该属性;


@Entity
public class User {

	@Id
	@GeneratedValue
	private long id;
	
	@Column(name="name")
	private String name;
	
	@OneToMany(cascade=CascadeType.ALL,mappedBy="user")//由多端维护关系
	private Set<Role> roles = new HashSet<Role>();
}

@Entity
public class Role {
	@Id
	@GeneratedValue
	private long id;
	@Column
	private String name;
	@ManyToOne
	private User user;
}

-------------------mappedBy 只保存一端
T1
执行:
        User user = new User();
        user.setName("zhangsan");
        
        Role r1= new Role();
        r1.setName("ADMIN");
        Role r2= new Role();
        r2.setName("EDITOR");
        //业务代码中双向设置关系
        user.getRoles().add(r1);
        user.getRoles().add(r2);
        r1.setUser(user);
        r2.setUser(user);
		
		session.save(user);
结果:
Hibernate: 
    insert 
    into
        User
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, user_id, id) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, user_id, id) 
    values
        (?, ?, ?)
执行3条语句,插入结果正确。将保存操作传递到多端了,然后进行了保存。

--------------------------------mappedBy 先保存多端,再保存一端
        User user = new User();
        user.setName("zhangsan");
        
        Role r1= new Role();
        r1.setName("ADMIN");
        Role r2= new Role();
        r2.setName("EDITOR");
        
        user.getRoles().add(r1);
        user.getRoles().add(r2);
        r1.setUser(user);
        r2.setUser(user);
        session.save(r1);
        session.save(r2);
        session.save(user);//无此句则报错,因为user为瞬时态,而role端无级联操作
结果:
Hibernate: 
    insert 
    into
        Role
        (name, user_id, id) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, user_id, id) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        User
        (name, id) 
    values
        (?, ?)
Hibernate: 
    update
        Role 
    set
        name=?,
        user_id=? 
    where
        id=?
Hibernate: 
    update
        Role 
    set
        name=?,
        user_id=? 
    where
        id=?
先保存两个role,然后保存user。role负责关系维护,又更新了关系外键。

---------------------mappedBy 只保存一端,并删除一端集合的一个数据 

执行:
        User user = new User();
        user.setName("zhangsan");
        
        Role r1= new Role();
        r1.setName("ADMIN");
        Role r2= new Role();
        r2.setName("EDITOR");
        //业务代码中双向设置关系
        user.getRoles().add(r1);
        user.getRoles().add(r2);
        r1.setUser(user);
        r2.setUser(user);
		
		session.save(user);
		user.getRoles().remove(r1);


结果:
Hibernate: 
    insert 
    into
        User
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, user_id, id) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        Role
        (name, user_id, id) 
    values
        (?, ?, ?)

没有进行删除操作。User不负责关系维护,操作失败。
当指定orphanRemoval=true时删除成功!


---------级联删除
--------------------直接删除一端(数据为T1操作后的数据)
        User user = session.get(User.class, 170l);
        session.remove(user);
		
结果:
Hibernate: 
    delete 
    from
        Role 
    where
        id=?
Hibernate: 
    delete 
    from
        Role 
    where
        id=?
Hibernate: 
    delete 
    from
        User 
    where
        id=?

删除了一端和所有多端。删除进行了级联传递,先删除多端的两个Role,然后删除用户。
此时确先删除了多端,然后删除一端?直接先删除一端是不可能的

--------------------直接删除多端
Role r = session.get(Role.class, 175l);
session.remove(r);
结果:
Hibernate:
delete
from
Role
where
id=?
执行成功。相当于执行了mantoone的删除

//删除
User user = session.get(User.class, 167l);
Role role = session.get(Role.class, 168l);
System.out.println(user.getName());
System.out.println(role.getName());
user.getRoles().remove(role);//当载入内存后,必须解除关系,再删除
session.remove(role);//删除成功