一、 多对一 ---- 单向
场景:用户和组;从用户角度来,多个用户属于一个组(多对一 关联)使用hibernate开发的思路:先建立对象模型(领域模型),把实体抽取出来。
目前两个实体:用户和组两个实体,多个用户属于一个组,那么一个用户都会对应于一个组,所以用户实体中应该有一个持有组的引用。
(一) 关联映射的本质:
将关联关系映射到数据库,所谓的关联关系是对象模型在内存中一个或多个引用。
(二) 实体类
User实体类:
public class User {
private int id;
private String name;
private Group group;
public Group getGroup() {return group; }
public void setGroup(Group group) {this.group = group;}
public int getId() {return id; }
public void setId(int id) { this.id = id;}
public String getName() {return name;}
public void setName(String name) { this.name = name;}}
Group实体类:
public class Group {
private int id;
private String name;
public int getId() {return id;}
public void setId(int id) { this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
实体类建立完后,开始创建映射文件,先建立简单的映射文件:
(三) xml方式:映射文件:
1、 Group实体类的映射文件:
<hibernate-mapping>
<class name="csy.model.Group">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
2、 User实体类的映射文件:
<hibernate-mapping>
<class name="csy.model.User">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<!--<many-to-one> 关联映射 多对一的关系
name:是维护的属性(User.group),这样表示在多的一端表里加入一个字段名称为group,
但group与SQL中的关键字重复,所以需要重新命名字段(column="groupid").这样这个字段(groupid)会作为外键参照数据库中group表(t_group也叫一的一端),也就是就在多的一端加入一个外键指向一的一端。 -->
<many-to-one name="group" column="groupid"/>
</class>
</hibernate-mapping>
3、 <many-to-one>标签:
<many-to-one name="group" column="groupid"/>
<many-to-one> 关联映射 多对一的关系
name:是维护的属性(User.group),这样表示在多的一端表里加入一个字段名称为group,但group与SQL中的关键字重复,所以需要重新命名字段(column="groupid").这样这个字段(groupid)会作为外键参照数据库中group表,也就是就在多的一端加入一个外键指向一的一端。
(四) annotation
Group(一的一端)注解只需要正常的注解就可以了,因为在实体类中它是被引用的。
User(多的一端):@ManyToOne来注解多一对的关键,并且用@JoinColumn来指定外键的字段名
@Entity
public class User {
private int id;
private String name;
private Group group;
@ManyToOne
@JoinColumn(name="groupId")
public Group getGroup() {
return group;
}
(五) 多对一 存储(先存储group(对象持久化状态后,再保存user)):
Group group = new Group();
group.setName("csy");
session.save(group); //存储Group对象。
User user1 = new User();
user1.setName("zhangsan");
user1.setGroup(group);//设置用户所属的组
User user2 = new User();
user2.setName("lisi");
user2.setGroup(group);//设置用户所属的组
//开始存储
session.save(user1);//存储用户
session.save(user2);
执行后hibernate执行以下SQL语句:
Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_user (name, groupid) values (?, ?)
Hibernate: insert into t_user (name, groupid) values (?, ?)
注意:如果上面的session.save(group)不执行,则存储不存储不成功。则抛出TransientObjectException异常。因为Group为Transient状态,Object的id没有分配值。
结果:persistent状态的对象是不能引用Transient状态的对象
以上代码操作,必须首先保存group对象,再保存user对象。我们可以利用cascade(级联)方式,不需要先保存group对象。而是直接保存user对象,这样就可以在存储user之前先把group存储了。利用cascade属性是解决TransientObjectException异常的一种手段。
(六) 重要属性-cascade(级联):
级联的意思是指定两个对象之间的操作联运关系,对一个对象执行了操作之后,对其指定的级联对象也需要执行相同的操作,取值:all、none、save-update、delete
1、 all:代码在所有的情况下都执行级联操作
2、 none:在所有情况下都不执行级联操作
3、 save-update:在保存和更新的时候执行级联操作
4、 delete:在删除的时候执行级联操作。
1、 xml
<many-to-one name="group" column="groupid" cascade="save-update"/>
2、 annotation
cascade属性:其值: CascadeType.ALL 所有
CascadeType.MERGE save + update
CascadeType.PERSIST
CascadeType.REFRESH
CascadeType.REMOVE
例如:
@ManyToMany(cascade={ CascadeType.ALL})
注意:cascade是一个数组,不要忘了花括号,并且cascade只是帮我们省了编程的麻烦而已,不要把它的作用看的太大