作业-树状结构设计

作业:树状结构的设计
在同一个类中使用OneToMany和ManyToOne

首先想数据库的模型,再想面向对象的模型,然后再来想怎么去做映射,做完映射在想怎么去做CRUD。

1.首先设计数据库的模型
应该是Id、parent_Id.单一父亲,好多孩子这就是一棵树。

数据库首先存在的属性有:
Id<int> parent_Id<int> name<String>

例子:
ID   Parent_ID   公司
1       null     分公司1
2       1        分公司2
3       2        分公司2_1

实体类:

package cn.edu.hpu.treeStruct;  

import java.util.HashSet;
import java.util.Set;  

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;  

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

}  

如何来理解这张表,我们假设有三张表(都是id、name)。
A、B、C假设B的父亲是A,B的孩子是C,B通过parent_id去参考父亲A的ID,
C通过parent_id去找父亲B。只不过是多张表合成一张表。然后每一个人
的parent_id都去参考另外一条记录了,也就是参考自身这张表。是
一对多和多对一的双向关联关系。

测试,输出的建表sql语句:
alter table Org 
        drop 
        foreign key FK136C4424F8DF5

drop table if exists Org

create table Org (
        id integer not null auto_increment,
        name varchar(255),
        parent_id integer,
        primary key (id)
    )

alter table Org 
        add index FK136C4424F8DF5 (parent_id), 
        add constraint FK136C4424F8DF5 
        foreign key (parent_id) 
        references Org (id)

添加测试:

@Test
public void testTreeAdd(){
    Org o=new Org();
    o.setName("总公司");
    Org o1=new Org();
    o1.setName("分公司1");
    Org o2=new Org();
    o2.setName("分公司2");
    Org o11=new Org();
    o11.setName("分公司1下公司1");
    Org o12=new Org();
    o12.setName("分公司1下公司2");  

    o.getChildren().add(o1);
    o.getChildren().add(o2);
    o.getChildren().add(o11);
    o.getChildren().add(o12);
    o11.setParent(o1);
    o12.setParent(o1);
    o1.setParent(o);
    o2.setParent(o);
    //可以先存父亲,再存孩子,也可以让Org的Childern设置CascadeType.ALL
        //这里用的是设置CascadeType.ALL,所以只存父亲就可以了
    sessionFactory=new AnnotationConfiguration().configure().buildSessionFactory();
    Session session=sessionFactory.openSession();
    session.beginTransaction();
    session.save(o);
    session.getTransaction().commit();
    session.close();
}  

输出的sql语句:
Hibernate: 
    insert 
    into
        Org
        (name, parent_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Org
        (name, parent_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Org
        (name, parent_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Org
        (name, parent_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Org
        (name, parent_id) 
    values
        (?, ?)
Hibernate: 
    update
        Org 
    set
        name=?,
        parent_id=? 
    where
        id=?
Hibernate: 
    update
        Org 
    set
        name=?,
        parent_id=? 
    where
        id=?

结果:
id    name            parent_id
1     总公司           null
2     分公司1下公司1   5
3     分公司1下公司2   5      
4     分公司2           1
5     分公司1           1

读取测试(用递归):
简单的方式就是Org的Childern设置fetch=FetchType.EAGER,最好的方式是递归。

首先用fetch=FetchType.EAGER测试:

@Test
public void testTreeLoad(){  

    sessionFactory=new AnnotationConfiguration().configure().buildSessionFactory();
    Session session=sessionFactory.openSession();
    session.beginTransaction();
    Org o =(Org) session.load(Org.class,1);
    Treeprint(o);
    session.getTransaction().commit();
    session.close();
}  

private void Treeprint(Org o) {
    System.out.println(o.getName());
    for(Org child:o.getChildren()){
        Treeprint(child);
    }
}  

测试结果:
Hibernate: 
    select
        org0_.id as id0_1_,
        org0_.name as name0_1_,
        org0_.parent_id as parent3_0_1_,
        children1_.parent_id as parent3_0_3_,
        children1_.id as id3_,
        children1_.id as id0_0_,
        children1_.name as name0_0_,
        children1_.parent_id as parent3_0_0_ 
    from
        Org org0_ 
    left outer join
        Org children1_ 
            on org0_.id=children1_.parent_id 
    where
        org0_.id=?
Hibernate: 
    select
        children0_.parent_id as parent3_0_1_,
        children0_.id as id1_,
        children0_.id as id0_0_,
        children0_.name as name0_0_,
        children0_.parent_id as parent3_0_0_ 
    from
        Org children0_ 
    where
        children0_.parent_id=?
Hibernate: 
    select
        children0_.parent_id as parent3_0_1_,
        children0_.id as id1_,
        children0_.id as id0_0_,
        children0_.name as name0_0_,
        children0_.parent_id as parent3_0_0_ 
    from
        Org children0_ 
    where
        children0_.parent_id=?
Hibernate: 
    select
        children0_.parent_id as parent3_0_1_,
        children0_.id as id1_,
        children0_.id as id0_0_,
        children0_.name as name0_0_,
        children0_.parent_id as parent3_0_0_ 
    from
        Org children0_ 
    where
        children0_.parent_id=?
Hibernate: 
    select
        children0_.parent_id as parent3_0_1_,
        children0_.id as id1_,
        children0_.id as id0_0_,
        children0_.name as name0_0_,
        children0_.parent_id as parent3_0_0_ 
    from
        Org children0_ 
    where
        children0_.parent_id=?
总公司
分公司1
分公司1下公司2
分公司1下公司1
分公司2

如何展现成树状?

@Test
public void testTreeLoad(){  

    sessionFactory=new AnnotationConfiguration().configure().buildSessionFactory();
    Session session=sessionFactory.openSession();
    session.beginTransaction();
    Org o =(Org) session.load(Org.class,1);
    Treeprint(o,0);
    session.getTransaction().commit();
    session.close();
}  

private void Treeprint(Org o,int level) {
    //level是构建树状前的缩进
    String preStr="";
    for(int i=0;i<level;i++){
        preStr+="----";
    }
    System.out.println(preStr+o.getName());
    for(Org child:o.getChildren()){
        Treeprint(child,level+1);
    }
}  

测试结果:
总公司
----分公司2
----分公司1
--------分公司1下公司2
--------分公司1下公司1

如果这棵树非常大我们用EAGER就不合适了,需要把它去掉了,什么时候需要(get)才从DB拿出。

也就是使用LAZY的方式,什么时候需要的时候才发送QL 从DB中获取

时间: 2025-01-12 00:15:18

作业-树状结构设计的相关文章

《Hibernate学习笔记十一》:树状结构设计

<Hibernate学习笔记十一>:树状结构设计 这是马士兵老师讲解Hibernate的一个作业题,树状结构设计,这是一个比较典型的例子,因此有必要写篇博文记录下. 树状结构的设计,它是在同一个类中使用了多对一(ManyToOne)和一对多(OneToMany). 在完成这个题目我们应该按照如下的步骤进行: 1.先思考数据库的模型应该是什么样的?? 数据库中的模型应该如下:即存在id p_id 2.思考面向对象的模型,及如何来进行映射??? 根据数据库中表的特点,对象应该有id name;由于

BZOJ3236: [Ahoi2013]作业 树状数组维护 莫队

水果~~~~ 关于四个while可行性的证明:区间有正确性所以不管那团小东西用没有duang~反它最终总会由于两次覆盖二准确 关于区间种数可行性的证明:他会在0 1间(或两边)来回跳动(过程中),最终会停在一个大于等于0的地方由于多次覆盖,最终也会趋于准确 #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<algorithm> #defin

【BZOJ3236】【AHOI2013】作业 线段树 分治 树状数组

题目描述 给你一个长度为\(n\)的数列,还有\(m\)个询问,对于每个询问\((l,r,a,b)\),输出1.区间\([l,r]\)有多少范围在\([a,b]\)的数:2.区间\([l,r]\)有多少范围在\([a,b]\)的权值. \(n\leq 100000,m\leq 1000000\) 题解 这道题莫队可以水过. 这里讲一个更优秀的算法. 建一棵权值线段树.每一个点存它代表的范围内所有数的下标. 一个询问对应权值线段树中的一些点.每个点要求出\([l,r]\)内的数的个数和不同的数的个

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

(POJ 3067) Japan (慢慢熟悉的树状数组)

Japan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29295   Accepted: 7902 Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coas

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

CF 313 DIV2 B 树状数组

http://codeforces.com/contest/313/problem/B 题目大意 给一个区间,问你这个区间里面有几个连续相同的字符. 思路: 表示个人用树状数组来写的...了解了树状数组的本质就行了. 当然用sum[r]-sum[l]也是可以的

Hdu5032 极角排序+树状数组

题目链接 思路:参考了题解.对询问进行极角排序,然后用树状数组维护一下前缀和即可. /* ID: onlyazh1 LANG: C++ TASK: test */ #include<bits/stdc++.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 typedef long long ll; const int maxn=1010; const int maxm=10