hibernate树状结构

树形结构:也就是目录结构,有父目录、子目录、文件等信息,而在程序中树形结构只是称为节点。
         一棵树有一个根节点,而根节点也有一个或多个子节点,而一个子节点有且仅有一个父节点(当前除根节点外),而且也存在一个或多个子节点。
         也就是说树形结构,重点就是节点,也就是我们需要关心的节点对象。
         节点:一个节点有一个ID、一个名称、它所属的父节点(根节点无父节点或为null),有一个或多的子节点等其它信息。
Hibernate将节点抽取出成实体类,节点相对于父节点是“多对一”映射关系,节点相对于子节点是“一对多”映射关系。
一、  节点实体类:
[java] 
/** * 节点*/ 
public class Node { 
    private int id; //标识符 
    private String name; //节点名称  
    private int level; //层次,为了输出设计    
    private boolean leaf; //是否为叶子节点,这是为了效率设计,可有可无 
    //父节点:因为多个节点属于一个父节点,因此用hibernate映射关系说是“多对一” 
    private Node parent; 
    //子节点:因为一个节点有多个子节点,因此用hibernate映射关系说是“一对多” 
    private Set children; 
  
    public int getId() {return id;} 
    public void setId(int id) {this.id = id;} 
    public String getName() {return name;} 
    public void setName(Stringname) {  this.name = name;} 
    public int getLevel() { return level;} 
    public void setLevel(int level) {this.level = level;} 
    public boolean isLeaf() {return leaf;} 
    public void setLeaf(boolean leaf) {this.leaf = leaf;} 
    public Node getParent() {return parent;} 
    public void setParent(Nodeparent) {this.parent = parent;} 
    public SetgetChildren() {return children;} 
    public void setChildren(Setchildren) {this.children = children;} 


二、  xml方式:映射文件:
 
[html] 
<class name="com.wjt276.hibernate.Node" table="t_node"> 
      <id name="id" column="id"> 
          <generator class="native"/> 
      </id> 
      <property name="name"/> 
      <property name="level"/> 
      <property name="leaf"/> 
<!— 一对多:加入一个外键,参照当前表t_node主键,    而属性parent类型为Node,也就是当前类,则会在同一个表中加入这个字段,参照这个表的主键--> 
      <many-to-one name="parent" column="pid"/> 
  <!--<set>标签是映射一对多的方式,加入一个外键,参照主键。--> 
      <set name="children" lazy="extra"inverse="true"> 
          <key column="pid"/> 
          <one-to-many class="com.wjt276.hibernate.Node"/> 
      </set>      
  </class> 

三、  annotation注解
因为树型节点所有的数据,在数据库中只是存储在一个表中,而对于实体类来说,节点对子节点来说是一对多的关系,而对于父节点来说是多对一的关系。因此可以在一个实体类中注解。如下
[java] 
@Entity 
public class Node { 
    private int id; // 标识符 
    private String name; // 节点名称 
    private int level; // 层次,为了输出设计 
    private boolean leaf; // 是否为叶子节点,这是为了效率设计,可有可无 
    // 父节点:因为多个节点属于一个父节点,因此用hibernate映射关系说是“多对一” 
    private Node parent; 
    // 子节点:因为一个节点有多个子节点,因此用hibernate映射关系说是“一对多” 
    private Set<Node> children = newHashSet<Node>(); 
    @Id 
    @GeneratedValue 
    public int getId() {return id;} 
    @OneToMany(mappedBy="parent") 
    public Set<Node>getChildren() {return children;} 
    @ManyToOne 
    @JoinColumn(name="pid") 
    public Node getParent() {return parent;} 
 } 


四、  测试代码:
[java] 
public class NodeTest extends TestCase { 
  //测试节点的存在 
  public void testSave1(){ 
      NodeManage.getInstanse().createNode("F:\\hibernate\\hibernate_training_tree"); 
  } 
  //测试节点的加载 
  public void testPrintById(){ 
      NodeManage.getInstanse().printNodeById(1); 
  }} 


五、  相应的类代码:
[java] 
public classNodeManage {   
    private static NodeManage nodeManage= newNodeManage(); 
    private NodeManage(){}//因为要使用单例,所以将其构造方法私有化 
    //向外提供一个接口 
    public static NodeManage getInstanse(){ 
        return nodeManage; 
    } 
    /**
     * 创建树
     *@param filePath 需要创建树目录的根目录
     */ 
    public void createNode(String dir) { 
        Session session = null;     
        try { 
            session =HibernateUtils.getSession(); 
            session.beginTransaction(); 
            
            File root = new File(dir); 
            //因为第一个节点无父节点,因为是null 
            this.saveNode(root, session, null,0); 
            
            session.getTransaction().commit(); 
        } catch (HibernateException e) { 
            e.printStackTrace(); 
            session.getTransaction().rollback(); 
        } finally { 
            HibernateUtils.closeSession(session); 
        }} 
    /**
     * 保存节点对象至数据库
     *@param file 节点所对应的文件
     *@param session session
     *@param parent 父节点
     *@param level 级别
     */ 
    public void saveNode(File file, Sessionsession, Node parent, int level) { 
        if (file == null ||!file.exists()){return;} 
        //如果是文件则返回true,则表示是叶子节点,否则为目录,非叶子节点 
        boolean isLeaf = file.isFile(); 
        Node node = new Node(); 
        node.setName(file.getName()); 
        node.setLeaf(isLeaf); 
        node.setLevel(level); 
        node.setParent(parent); 
        
        session.save(node); 
        
        //进行循环迭代子目录 
        File[] subFiles = file.listFiles(); 
        if (subFiles != null &&subFiles.length > 0){ 
            for (int i = 0; i <subFiles.length ; i++){ 
                this.saveNode(subFiles[i],session, node, level + 1); 
            }}} 
    /**
     * 输出树结构
     *@param id
     */ 
    public void printNodeById(int id) { 
  
        Session session = null; 
        
        try { 
            session =HibernateUtils.getSession(); 
            session.beginTransaction(); 
            
            Node node =(Node)session.get(Node.class, 1); 
            
            printNode(node); 
            
            session.getTransaction().commit(); 
        } catch (HibernateException e) { 
            e.printStackTrace(); 
            session.getTransaction().rollback(); 
        } finally { 
            HibernateUtils.closeSession(session); 
        }       
    }   
    private void printNode(Node node) {     
        if (node == null){  return; } 
        int level = node.getLevel(); 
        if (level > 0){ 
            for (int i = 0; i < level; i++){ 
                System.out.print("  |"); 
            } 
            System.out.print("--");             
        } 
        System.out.println(node.getName() +(node.isLeaf() ? "" : "[" + node.getChildren().size() +"]")); 
        Set children = node.getChildren(); 
        for (Iterator iter =children.iterator(); iter.hasNext(); ){ 
            Node child = (Node)iter.next(); 
            printNode(child); 
        }}} 

 作业-学生、课程、分数的映射关系
一、        设计
1、  实体类(表)
2、  导航(编程方便)
a)        通过学生 取出 学生所先的课程
b)        但是通过课程 取出 学该课程的 学生不好。学的学生太多
c)         确定编程的方式
3、  可以利用联合主键映射可以,
a)        学生生成一个表
b)        课程生成一个表
c)         再生成一个表,主键是联合主键(学生ID、课程ID) + 学生共生成一个表
4、  也可以利用一对多,多对多 都可以(推荐)
a)        学生生成一个表
b)        课程生成一个表
c)         分数生成一个表,并且有两个外键,分别指向学生、课程表
二、        代码:
* 课程
[java]
@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(Stringname) {this.name = name;} 


 
* 分数
[java]
@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 StudentgetStudent() {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(Studentstudent) {this.student = student;} 
  public void setCourse(Coursecourse) {this.course = course;} 
  public void setId(int id) { this.id = id;} 

 
* 学生通过课程可以导航到分数
[java]
@Entity 
public class Student { 
  private int id; 
  private String name; 
  private Set<Course> courses = newHashSet<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 voidsetCourses(Set<Course> courses) {this.courses = courses;} 
  public void setId(int id) { this.id = id;} 
  public String getName() {return name;} 
  public void setName(Stringname) {this.name = name;} 


 
三、        注意
在Student实体类中的使用的第三方表使用了两个字段,而hibernate会使这两个字段生成联合主键,这并不是我们需要的结果,因为我们需要手动到数据库中修改。这样才可以存储数据,否则数据存储不进去。这可能是hibernate的一个小bug


作者:liushaohan01
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值