hibernate树形结构(重点)
树形结构:也就是目录结构,有父目录、子目录、文件等信息,而在程序中树形结构只是称为节点。
一棵树有一个根节点,而根节点也有一个或多个子节点,而一个子节点有且仅有一个父节点(当前除根节点外),而且也存在一个或多个子节点。
也就是说树形结构,重点就是节点,也就是我们需要关心的节点对象。
节点:一个节点有一个ID、一个名称、它所属的父节点(根节点无父节点或为null),有一个或多的子节点等其它信息。
Hibernate将节点抽取出成实体类,节点相对于父节点是“多对一”映射关系,节点相对于子节点是“一对多”映射关系。
一、 annotation注解
因为树型节点所有的数据,在数据库中只是存储在一个表中,而对于实体类来说,节点对子节点来说是一对多的关系,而对于父节点来说是多对一的关系。因此可以在一个实体类中注解。如下
@Entity
public class Org {
private int id;
private String name;
private Set<Org> children = new HashSet<Org>();
private Org parent;
@Id
@GeneratedValue
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;
}
@OneToMany(cascade=CascadeType.ALL,mappedBy="parent",fetch=FetchType.EAGER)
public Set<Org> getChildren() {
return children;
}
public void setChildren(Set<Org> children) {
this.children = children;
}
@ManyToOne
@JoinColumn(name="parent_id")
public Org getParent() {
return parent;
}
public void setParent(Org parent) {
this.parent = parent;
}
}
二、 xml方式:映射文件:
<class name="csy.model.Org">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<!— 一对多:加入一个外键,参照当前表org主键, 而属性parent类型为Org,也就是当前类,则会在同一个表中加入这个字段,参照这个表的主键-->
<many-to-one name="parent" column="parent_id"/>
<!-- <set>标签是映射一对多的方式,加入一个外键,参照主键。-->
<set name="children" lazy="extra" inverse="true">
<key column="parent_id"/>
<one-to-many class="csy.model.Org"/>
</set>
</class>
三、 测试代码:
@Test
public void testLoad(){
testSave();
Session session = sessionFactory.openSession();
session.beginTransaction();
Org o = (Org)session.load(Org.class, 1);
print(o,0);
session.getTransaction().commit();
session.close();
}
private void print(Org o,int level){
String preStr = "";
for(int i=0;i<level;i++){
preStr +="----";
}
System.out.println(preStr+o.getName());
for(Org child:o.getChildren()){
print(child,level+1);
}
}
学生、课程、分数的映射关系
一、 设计
1、 实体类(表)
2、 导航(编程方便)
a) 通过学生 取出 学生所先的课程
b) 但是通过课程 取出 学该课程的 学生不好。学的学生太多
c) 确定编程的方式
3、 可以利用联合主键映射可以,
a) 学生生成一个表
b) 课程生成一个表
c) 再生成一个表,主键是联合主键(学生ID、课程ID) + 学生共生成一个表
4、 也可以利用一对多,多对多 都可以(推荐)
a) 学生生成一个表
b) 课程生成一个表
c) 分数生成一个表,并且有两个外键,分别指向学生、课程表
课程代码:
@Entity
public class Course {
private int id;
private String name;
@Id
@GeneratedValue
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;}}
分数代码:
@Entity
@Table(name = "score")
public class Score {
private int id;
private int score;
private Student student;
private Course course;
@Id
@GeneratedValue
public int getId() {return id;}
@ManyToOne
@JoinColumn(name = "student_id")
public Student getStudent() {return student;}
@ManyToOne
@JoinColumn(name = "score_id")
public Course getCourse() { return course;}
public int getScore() { return score;}
public void setScore(int score) {this.score = score;}
public void setStudent(Student student) {this.student = student;}
public void setCourse(Course course) {this.course = course;}
public void setId(int id) { this.id = id;}}
学生通过课程可以导航到分数
@Entity
public class Student {
private int id;
private String name;
private Set<Course> courses = new HashSet<Course>();
@Id
@GeneratedValue
public int getId() {return id;}
@ManyToMany
@JoinTable(name = "score", //此表就是Score实体类在数据库生成的表叫score
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
public Set<Course> getCourses() {return courses;}
public void setCourses(Set<Course> courses) {this.courses = courses;}
public void setId(int id) { this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}}
三、 注意
在Student实体类中的使用的第三方表使用了两个字段,而hibernate会使这两个字段生成联合主键,这并不是我们需要的结果,因此我们需要手动到数据库中修改。这样才可以存储数据,否则数据存储不进去。