(7)onetomany双向:CURD
一、Save
Group类
@Entity
@Table(name="_Group")//对表重命名(group是关键字,不能作为表名,所以要对其重命名)
public class Group {
private int id;
private String name;
private Set<User> user=new HashSet<User>();
/*
* 选set的理由:一个组中含有多个用户,它是不同的用户组成的集合。list与数组很像,可以有重复数据。
* map需要个key,这里不用指定。set元素不能重复,也没key最合适
*/
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@OneToMany(mappedBy="group")
public Set<User> getUser() {
return user;
}
public void setUser(Set<User> user) {
this.user = user;
}
}
User类
@Entity
@Table(name="_User")//对表重命名
public class User {
private int id;
private String name;
private Group group;
@Id //必须加在getId上面
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@ManyToOne
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
}
在保存时需要注意的是:要将两侧的关联在类层次设好。并且哪些是应该先存储的,哪些是应该后存储的,比如在该例子中一个组中有多个用户,在用户端有外键,则必须先将组先存储,再存储与该组有关的用户。即要将两侧的基本属性和关联属性(集合或者类对象)设置好
@org.junit.Test
public void GroupSave() {
User u=new User();
u.setName("u1");
User u2=new User();
u2.setName("u2");
Group g=new Group();
g.setName("g1");
g.getUser().add(u);
g.getUser().add(u2);
u.setGroup(g);//存user必须知道所属的组
u2.setGroup(g);
Session session=sf.getCurrentSession();
session.beginTransaction();
session.save(g);
session.save(u);
session.save(u2);
session.getTransaction().commit();
}
二、Read
/*
* cascade.all影响的是cud,不管r.
* fetch:负责读取
*fetch一般情况,取默认的方式即可。一对多设lazy 多对一设eager
*/
@org.junit.Test
public void UserGet() {
GroupSave();
Session session=sf.getCurrentSession();
session.beginTransaction();
User u=(User) session.get(User.class, 1);//manyToOne默认(无论有无cascade={CascadeType.ALL})会把1方取出,也符合常理:取出一个用户,知道他是哪组、组的名称等信息
System.out.println(u.getGroup().getName());
session.getTransaction().commit();
//System.out.println(u.getGroup().getName());//在默认状态,因为get已经获取到了1端的数据,所以写在外面或者写在里面都可以。
}
@org.junit.Test
public void GroupGet() {
GroupSave();
Session session=sf.getCurrentSession();
session.beginTransaction();
Group g=(Group) session.get(Group.class, 1);//默认不会将用户信息取出,若要取出,在@OneToMany(mappedBy="group",cascade={CascadeType.ALL},fetch=FetchType.EAGER)
/*
* 当fetch=FetchType.LAZY时,不会获取多端的数据。
* 此时,什么时候获取多端的数据?当调用多端的方法时,才会select
*/
System.out.println(g.getUser().size());//这句话在fetch=FetchType.LAZY状态时,不能写在session外,因为没有session不能select到
session.getTransaction().commit();
}
三、Update
update:一定是先get到对象,然后对该对象进行操作。该对象会放入缓存中,当对其set时,会检测set的是否和之前信息相同,若相同,则不更新。若不同,则更新。比如在这个例子中user参考group,那么当user类中有group类对象,对其设置新属性也会触发update。无论是否有级联操作。
@org.junit.Test//user表和group表均会做更新,
public void UserUpdate() {
UserSave();
Session session=sf.getCurrentSession();
session.beginTransaction();
User u=(User) session.get(User.class, 1);
u.setName("oo");
u.getGroup().setName("ll");
session.getTransaction().commit();
}
四、Delete(特别注意)
若要删除的类对象中类没有级联操作,则不会影响其他的表。若有级联操作会影响其他的表。解决方法,①将其对应的级联关系字段设为空,如UserDelete1()。
②用HQL无论有无级联,都不会影响其他的表。(这也是在级联中比较好的解决方式)
@org.junit.Test
/*
* 对于双向关联中删除,需要注意
* 在本例中,要删除id=1的用户,因为user(cascade={CascadeType.ALL}),所以它会把group对应的id删掉。
* 若要删除group表中对应的id对应记录,group表cascade={CascadeType.ALL},会先把user表的外键是它的记录删掉,
* 在本例中,相当于删除了group和user中的所有记录。
* 这是在编程过程中不允许的。【原意是只删除一条记录】
*/
public void UserDelete() {
UserSave();
Session session=sf.getCurrentSession();
session.beginTransaction();
User u=(User) session.get(User.class, 1);
session.delete(u);
session.getTransaction().commit();
}
@org.junit.Test
/*
* 解决上述问题的方法一:打破这种外键的关系。删除多端。
*
*/
public void UserDelete1() {
UserSave();
Session session=sf.getCurrentSession();
session.beginTransaction();
User u=(User) session.get(User.class, 1);
u.setGroup(null);//这样,使得这条user记录与group没有关系
session.delete(u);
session.getTransaction().commit();
}
@org.junit.Test
/*
* 解决上述问题的方法二:使用hql。删除多端。
*
*/
public void UserDelete2() {
UserSave();
Session session=sf.getCurrentSession();
session.beginTransaction();
session.createQuery("delete from User u where u.id=1").executeUpdate();
session.getTransaction().commit();
}
//删除1端,也会级联操作。多数情况这也是需要级联操作的,所以不必做更多的操作。