hibernate树形结构

  树形结构:也就是目录结构,有父目录、子目录、文件等信息,而在程序中树形结构只是称为节点。

         一棵树有一个根节点,而根节点也有一个或多个子节点,而一个子节点有且仅有一个父节点(当前除根节点外),而且也存在一个或多个子节点。

         也就是说树形结构,重点就是节点,也就是我们需要关心的节点对象。

         节点:一个节点有一个ID、一个名称、它所属的父节点(根节点无父节点或为null),有一个或多的子节点等其它信息。

Hibernate将节点抽取出成实体类,节点相对于父节点是“多对一”映射关系,节点相对于子节点是“一对多”映射关系。

一、  节点实体类:

/** * 节点*/
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方式:映射文件:

  

<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注解

因为树型节点所有的数据,在数据库中只是存储在一个表中,而对于实体类来说,节点对子节点来说是一对多的关系,而对于父节点来说是多对一的关系。因此可以在一个实体类中注解。如下

@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;}
 }


四、  测试代码:

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


五、  相应的类代码:

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)         分数生成一个表,并且有两个外键,分别指向学生、课程表

二、        代码:

* 课程

@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;}
}


 

* 分数

@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;}
}

 

* 学生通过课程可以导航到分数

@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


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值