欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JPA实体关系映射

程序员文章站 2022-04-23 13:04:01
...
  今天做东西的时候想用jpa实现商品的repository,有四个表,goods,goods_image,goods_type,goods_and_image
  goods与goods_image为一对多关系,goods_image中存放goods_id和image,一个goods_id可以有多个Image;
  goods与goods_type为多对多关系,goods_and_type存放goods_id和goods_type,每个goods_id可以有多种type,每
个type也是有多种商品;

数据表

create table goods
(
  id          int auto_increment
    primary key,
  name        varchar(50)                         not null,
  description varchar(255)                        null,
  price       int                                 not null,
  status      int default '0'                     null,
  create_time timestamp default CURRENT_TIMESTAMP not null,
  num         int                                 null
);

create table goods_image
(
  `_id`    int auto_increment
    primary key,
  goods_id int          not null,
  remark   varchar(255) null,
  image    varchar(255) not null
);

create table type
(
  type_id int auto_increment
    primary key,
  name    varchar(100)    null,
  parent  int default '0' not null
  comment '父类别 0代表*类别'
);
create table goods_and_type
(
  id       int auto_increment
    primary key,
  goods_id int not null,
  types_id int not null 
);

create table goods_and_image
(
  goods_id int not null,
  image_id int not null,
  primary key (goods_id, image_id)
);
最后一个表goods_and_image是我用来实现双向一对多映射;
注意一下 type表中主键是type_id,而goods_and_type表中叫types_id,这两个不一致,目的是来详细测试的。

关系映射

关系映射其实就是表与表的join,单向一对多(goods –>> goods_image)就是说只能从goods一边向image连表查询,双向一对多就是说既能从goods查到image又能从image查到goods,从类上就表现为一个类持有另一个类的引用;例如下面的goods就有一个属性images,代表能通过查goods查到images;如果通过查某个image,可以知道对应的那一个goods,这就是双向一对多映射
多对多(goods –>> goods_type):单向的多对多就是说只能通过goods查到对应的goods_type,感觉和单向一对多差不多(个人观点,有问题请在评论区告诉我)
而双向的多对多就不赘述了,看到这应该已经理解了

单向一对多 比如goods和goods_image

单向的一对多映射较简单,在goods的images属性上加**@OneToMany(mappedBy = "goods")**就可以了
@Entity //JPA的实体 必须
@Table //可以加属性 表示对应数据库的表名 默认为类名 必须
@Data //lombok插件的注解,帮助生成getter等方法 非必须但需要手动写getter、setter等方法
public class Goods {

    @Id//标志主键 必须
    @Column(name = "id") // 表示属性对应数据表的列名,默认为属性名,属性与列名一致时非必须
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;
    private String description;
    private int price;
    private int status;
    private int num;

    @Column(name = "create_time") //此时属性与列名不一致,必须
    private Date createTime;

    /**
     * mappedBy 表示 一对多的映射关系由 “多”的一方维护
     *  就是说在image表中每一行存image及对应的goods_id
     *  mappedy的值应该是 当前表 goods与image的连表条件对应的Entity属性
     *  连表条件是 goods.id = goods_image.goods_id,
     *  所以这里应该是goods_image表中goods_id对应的属性goodsId
     *
     * 不加mappedy表示 用一张新表来维护,后面讲双向会讲
     */
    @OneToMany(mappedBy = "goodsId")
    //我不加这个注释会抛异常 延迟初始化失败
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Image> images;

}
@Data
@Entity
@Table(name = "goods_image")
public class Image {

    @Id
    @GeneratedValue
    private int id;

    private String remark;
    private String image;

    /**
     * 单向一对多
     */
    @Column(name = "goods_id")
    // 这个属性名就是goods中 mappedy的值
    private int goodsId;

}
// 单向一对多时,‘多’方不需要加额外注解

双向一对多

@Data
@Entity
@Table(name = "goods_image")
public class Image {

    @Id
    @GeneratedValue
    private int id;

    private String remark;
    private String image;

    @ManyToOne(fetch = FetchType.EAGER)
    @LazyCollection(LazyCollectionOption.FALSE)
    private Goods goods;

}

@Entity
@Table
@Data
public class Goods {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;
    private String description;
    private int price;
    private int status;
    private int num;

    @Column(name = "create_time")
    private Date createTime;

    /*
     * 双向一对多
     *   我下面是通过一张新表goods_and_image实现的
     *      连接条件:goods.id = goods_and_image.goods_id
     *          and goods_and_image.image_id = goods_image.image_id
     *   也可以不新建表 不过需要 goods_image 与 goods 连接之后 再与 goods_image 连接
     *      连接条件:goods.id = goods_image.goods_id
     *          and goods_image.goods_id = goods.id
     *
     * 我这是新建一张goods_and_image的实现 代码如下
     *   @JoinTable
     *       name属性表示连表的目标表
     *          当前表需要先join goods_and_type 再join goods_type, name 值就是goods_and_type
     *       joinCloumns 它的值是一个列表 可以是多个@JoinColumn
     *          @JoinColumn 每个@JoinColumn是一个连表条件
     *              name goods_and_image表中的与当前表连接的字段 goods_id
     *              referencedColumnName 当前表中参与连接的字段 id
     *              上面两个值都需要是数据表中的字段 JPA可以自动转换驼峰式命名:假如name写成goodsId也可以,
     *                  因为JPA会转换成goods_id
     *       inverseJoinColumns 和 joinCloumns 差不多
     *          @JoinColumn
     *              name 还是中间那个表(goods_and_image)中的字段
     *                  不过joinCloumns中的name是当前表与goods_and_image的连接的字段
     *                  但 inverseJoinColumns 中的 name 是
     *                  goods_and_image 中与另一边的表goods_image 连接的字段 image_id
     *              referencedColumnName 是 另一边的表(goods_image)被连接的字段 id
     * */
    @OneToMany
    @LazyCollection(LazyCollectionOption.FALSE)
    @JoinTable(name = "goods_and_image",
            joinColumns = {@JoinColumn(name = "goodsId", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "image_id", referencedColumnName = "id")})
    private List<Image> images;

}

多对多

单向多对多其实和双向的写法一样,这里给的代码是双向多对多的
单向的就是去掉不需要的那边的ManyToMany注解
@Entity
@Table
@Data
public class Goods {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;
    private String description;
    private int price;
    private int status;
    private int num;

    @Column(name = "create_time")
    private Date createTime;

    /*
    * 多对多
    * 其实单向多对多和上面双向OneToMany的写法是差不多的,
    *   只需要在单向多对多的主动的一边注解@ManyToMany
    *   具体的值根据上面讲的写就好了
    * 因为只从一边来讲 OneToMany 和 ManyToMany 是一样的
    *
    * 而双向的多对多 其实就是在另一边也加上ManyToMany注解
    *   只不过 另一边的注解 以另一边为第一人称。。。。
    *   (我表述能力可能有点问题 但我也想不到更好的表述了)
    * */
    @ManyToMany
    @LazyCollection(LazyCollectionOption.FALSE)
    @JoinTable(name = "goods_and_type",
            joinColumns = {@JoinColumn(name = "goods_id")},
            inverseJoinColumns = {@JoinColumn(referencedColumnName = "type_id", name = "types_id")})
    private List<GoodsType> goodsTypes;
}

@Data
@Entity
@Table(name = "type")
public class GoodsType {

    @Id
    @Column(name = "type_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;
    private int parent;

    @ManyToMany
    @JoinTable(name = "goods_and_type", joinColumns = {@JoinColumn(name = "types_id")},
            inverseJoinColumns = {@JoinColumn(referencedColumnName = "id", name = "goods_id")})
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Goods> goods;
}
相关标签: jpa