zoukankan      html  css  js  c++  java
  • hibernate关联映射

    本文可作为北京尚学堂马士兵hibernate课程的学习笔记。


    hibernate的映射,主要分为一对一,一对多,多对一,多对多,同一时候还要单向与双向的差别。


    OK,不要纠结于名字,我们開始看样例。


    一对一单向

    老公是一个实体,老婆也是一个实体。
    一个老公仅仅有一个老婆,同一时候一个老婆也仅仅有一个老公。
    上面的关系就叫做一对一。


    什么叫单向呢。
    看代码:

    package com.bjsxt.hibernate;
    
    @Entity
    public class Husband {
        private int id;
        private String name;
        private Wife wife;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        
        @OneToOne
        @JoinColumn(name="wifeId")
        public Wife getWife() {
            return wife;
        }
        //省略get set
    }
    
    
    package com.bjsxt.hibernate;
    
    @Entity
    public class Wife {
        private int id;
        private String name;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        //省略get set
    }


    看上面的代码,老公里面有老婆的引用,而老婆里面并没有老婆的引用。
    换句话说在代码层次上,依据老公我们能够获得他的老婆,可是依据老婆无法获得老公。(这就是单向)

    我们看看它执行的代码
    package com.bjsxt.hibernate;
    
    import org.hibernate.cfg.AnnotationConfiguration;
    import org.hibernate.tool.hbm2ddl.SchemaExport;
    
    public class Test {
        public static void main(String[] args) {
            new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);    
        }
    }
    在hibernate的配置文件中
    加上
    <property name="hbm2ddl.auto">update</property>
    结果
    19:41:04,229 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Husband (
            id integer not null auto_increment,
            name varchar(255),
            wifeId integer,
            primary key (id)
        )
    19:41:04,549 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Wife (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    19:41:04,880 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Husband
            add index FKAEEA401B109E78ED (wifeId),
            add constraint FKAEEA401B109E78ED
            foreign key (wifeId)
            references Wife (id)

    先给husband加了一个字段,wifeId,然后让他作为外键引用wife表的id字段。
    大家能够看到,@JoinColumn(name="wifeId")这个元标签指示了husband表内部那那个关联字段的名字。
    假设没有这个元标签呢?
    那么关联字段就是是:wife_id。

    即tableName_primarykey。
    假设把 @onetoone写到Wife里(husband里没有onotoone的标签),那么我们就能从wife获得husband了(在代码层次)。



    一对一双向

    假设我既想从husband里取得wife,也想从wife里取得husband。那咋办?


    把husband里的标签复制一遍就OK了嘛。


    package com.bjsxt.hibernate;
    
    @Entity
    public class Wife {
        private int id;
        private String name;
        private Husband husband;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        
        @OneToOne
        @JoinColumn(name="husbandId")
        public Husband getHusband() {
            return husband;
        }
    
    }

    OK,上面的代码里,wife也能够取到husband了。
    我们看看hibernate生成的sql
    create table Husband (
            id integer not null auto_increment,
            name varchar(255),
            wifeId integer,
            primary key (id)
        )
    19:53:20,487 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Wife (
            id integer not null auto_increment,
            name varchar(255),
            husbandId integer,
            primary key (id)
        )
    19:53:20,824 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Husband
            add index FKAEEA401B109E78ED (wifeId),
            add constraint FKAEEA401B109E78ED
            foreign key (wifeId)
            references Wife (id)
    19:53:21,421 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Wife
            add index FK292331CE01A6E1 (husbandId),
            add constraint FK292331CE01A6E1
            foreign key (husbandId)
            references Husband (id)
    看见了吧,wife里面有外键,husband里面也有外键!
    这不是冗余了嘛。
    把wife类改成以下的样子
        @OneToOne(mappedBy="wife")
        public Husband getHusband() {
            return husband;
        }
    这个mappedBy的意思是说,我(Wife这个类)和husband这个类是一对一关联的,可是关联的外键由husband类的getWife方法控制。
    执行一下。
    20:03:18,611 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Husband (
            id integer not null auto_increment,
            name varchar(255),
            wifeId integer,
            primary key (id)
        )
    20:03:18,618 ERROR org.hibernate.tool.hbm2ddl.SchemaExport:348 - Unsuccessful: create table Husband (id integer not null auto_increment, name varchar(255), wifeId integer, primary key (id))
    20:03:18,618 ERROR org.hibernate.tool.hbm2ddl.SchemaExport:349 - Table 'husband' already exists
    20:03:18,619 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Wife (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    20:03:18,933 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Husband
            add index FKAEEA401B109E78ED (wifeId),
            add constraint FKAEEA401B109E78ED
            foreign key (wifeId)
            references Wife (id)
    数据库里,wife表里没有外键了。
    可是,在代码层次我们依旧能够从Wife类里获得Husband。



    注意上面的 @OneToOne(mappedBy="wife")
    仅仅有是双向关联,最好就都写上mappedBy,两张表有一个外键就够了。




    多对一单向关联

    每个人都会有非常多个梦想,可是每个梦想仅仅属于某一个详细的人。
    我们先无论java代码上怎样实现,在数据库里。
    上面的两张表,一个是person,里面就是id,name
    再就是dream表,一个id,一个description。
    那么它们的外键放在哪张表里呢?


    放在dream里,换言之,dream表里有一个字段叫personId。


    这个的原因,不用解释。


    全部一对多,多对一的关系,在数据库里,外键都是放在多的一方里的。
    为什么。自己想。




    看代码

    package com.bjsxt.hibernate;
    
    @Entity
    public class Dream {
        private int id;
        private String description;    
        private Person person;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        @ManyToOne
        @JoinColumn(name="personId")
        public Person getPerson() {
            return person;
        }
        //省略get set
    }
    
    
    package com.bjsxt.hibernate;
    
    @Entity
    public class Person {
        private int id;
        private String name;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }    
        //省略get set
    }
    从代码层次上看"多对一单向"
    就是我能够从多的一方(dream)里获得一的那一方(person)。


    由于是单向,所以不能从person获得他全部的dream。
    OK,生成的表里,dream里有personid。

    20:20:21,970 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Dream (
            id integer not null auto_increment,
            description varchar(255),
            personId integer,
            primary key (id)
        )
    20:20:22,264 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Person (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    20:20:22,765 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table Dream
            add index FK3F397E3C1409475 (personId),
            add constraint FK3F397E3C1409475
            foreign key (personId)
            references Person (id)



    一对多单向关联

    还是人与梦想的样例。
    我想在代码层次,通过人获得他的全部的梦想,怎么办?
    首先在dream类里删除person的引用
    package com.bjsxt.hibernate;
    
    @Entity
    public class Person {
        private int id;
        private String name;
        private Set<Dream> dreams=new HashSet<>();
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
    
        @OneToMany
        @JoinColumn(name="psrsonId")
        public Set<Dream> getDreams() {
            return dreams;
        }    
    }


    OK,大功告成。


    建表语句和上面的一样。
    装dream的集合类为什么是set?

    list行不,map行不?
    都行。
    可是记着,数据库里面的记录是无序且不相等的。
    你说用哪个?




    无论是oneToMany还是manyToMany,加的 @JoinColumn(name="abc")
    都是在多的一方增加指向少的一方的名叫abc的外键。




    一对多双向关联(多对一双向关联)

    以下的样例,大家猜也猜到了,我既想从dream获得它所属的person,还想从person获得他全部的dream。
    我们看代码:
    package com.bjsxt.hibernate;
    
    @Entity
    public class Dream {
        private int id;
        private String description;
        
        private Person person;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @ManyToOne
        @JoinColumn(name="personId")
        public Person getPerson() {
            return person;
        }
    }
    
    package com.bjsxt.hibernate;
    
    @Entity
    public class Person {
        private int id;
        private String name;
        private Set<Dream> dreams=new HashSet<>();
    
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
    
        @OneToMany(mappedBy="person")
        public Set<Dream> getDreams() {
            return dreams;
        }
    }
    ok,我们能够在代码里,通过dream获得person也能够通过person获得dream



    多对多单向关联

    样例非常easy,一个老师能够教多个学生,一个学生能够被多个老师教。
    单向是说,要么老师能"知道"自己的学生,要么学生能知道自己的老师。
    我们先看老师能"知道"自己学生的代码。

    package com.bjsxt.hibernate;
    
    @Entity
    public class Student {
        private int id;
        private String name;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
    }
    OK,学生里面没有老师的引用。
    package com.bjsxt.hibernate;
    
    @Entity
    public class Teacher {
        private int id;
        private String name;
        private Set<Student> students = new HashSet<Student>();
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        
        @ManyToMany
        @JoinTable(name="t_s",
            joinColumns={@JoinColumn(name="teacher_id")},
            inverseJoinColumns={@JoinColumn(name="student_id")}
            )
        public Set<Student> getStudents() {
            return students;
        }
    }
    看结果:
    21:10:35,854 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Student (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    21:10:36,192 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table Teacher (
            id integer not null auto_increment,
            name varchar(255),
            primary key (id)
        )
    21:10:36,643 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        create table t_s (
            teacher_id integer not null,
            student_id integer not null,
            primary key (teacher_id, student_id)
        )
    21:10:36,947 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table t_s
            add index FK1BF68BF77BA8A (teacher_id),
            add constraint FK1BF68BF77BA8A
            foreign key (teacher_id)
            references Teacher (id)
    21:10:37,588 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport:377 -
        alter table t_s
            add index FK1BF68AEDC6FEA (student_id),
            add constraint FK1BF68AEDC6FEA
            foreign key (student_id)
            references Student (id)
    21:10:38,263  INFO org.hibernate.tool.hbm2ddl.SchemaExport:268 - schema export complete
    

    我们看看生成的t_s表和里面的字段名称应该就能明确 @JoinTable的作用
    它就是在manytomany时,指定第三张表的表名和字段。


    joinColumns 指的是指向自己这个类的字段名
    inverseJoinColumns inverse是反向的意思 所以这个标签就是运行另外那个类的字段
    假设没有 @JoinTable这个标签,会是什么样子呢?大家自己试一下。
    另外,上面的代码是从老师到学生,大家再试试从学生到老师。


    多对多双向关联

    在上面的样例里
    改变student,给它加上teacher的引用。

    package com.bjsxt.hibernate;
    
    
    @Entity
    public class Student {
        private int id;
        private String name;
        private Set<Teacher> teachers=new HashSet<>();
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        
        //记着 双向的时候 就加上mappedBy
        @ManyToMany(mappedBy="students")
        public Set<Teacher> getTeachers() {
            return teachers;
        }
    
    }


    glt likes dlf

    dlf likes glt

    oneToOne



  • 相关阅读:
    机器学习介绍
    Day03 作业
    Python函数基础
    Python练习
    耳机 线控 控制播放
    edittext 底线颜色
    从service启动activity startActivity慢 的解决方案
    国产手机没有google services 和google play崩溃,判断google services是否存在
    检测耳机插入和拔出
    获取view宽高
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6946627.html
Copyright © 2011-2022 走看看