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;
}
上一篇: ES6块级作用域详解
推荐阅读
-
EF(EntityFramework)与mysql使用,取数据报错,linq实体映射错误
-
Python ORM框架SQLAlchemy学习笔记之关系映射实例
-
Hibernate关联关系映射之继承映射
-
浅谈hibernate中多表映射关系配置
-
浅谈Java实体对象的三种状态以及转换关系
-
Hibernate实现many-to-many的映射关系
-
详解PHP的Laravel框架中Eloquent对象关系映射使用
-
研究Python的ORM框架中的SQLAlchemy库的映射关系
-
Python ORM框架SQLAlchemy学习笔记之关系映射实例
-
netcore 2.2 使用 AutoMapper 实现实体之间映射