工作中遇到的了,然后在网上也看了很多人写的,感觉挺乱的,自己梳理总结下;
1.OneToMany
分成两种,一种是双向的,一种是单向的;比如车(Car)和 车主(Owner),这里假设,一个车只能有一个车主,一个车主可以有多个车;双向的关系:通过车可以找到车对应的主人,而通过车主,可以获取到车主名下所有的车信息;而如果是单向的一对多的关系:通过车主可以找到车主名下的所有车,却不能通过车反过来找到对应的车主;这就是两者的区别;
1>单向的一对多的实现
数据库表结构
Owner Entity定义如下,其中cars中JoinColumn name属性指的是Car表的关联外键,这里是"owner_id",referencedColumnName是当前实体也就是Owner中的主键,这里是id;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@OneToMany
@JoinColumn(name="owner_id", referencedColumnName="id")
private Set<Car> cars = new HashSet<>();
这里如果不加JoinColumn的话,默认会使用一个中间表来处理的,我把这一行去掉之后,重新调用就报错了,如下图所示
说明默认的中间表是两者名字做了个连接,以下划线来分割;
Car Entity 是默认的定义,如下所示
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "owner_id")
private Long ownerId;
使用swagger来测试下,最终结果如图所示
2>双向一对多关系
实体的定义跟单向的有一些区别,如下所示
public class Owner implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "owner")
private Set<Car> cars = new HashSet<>();
这里的mappedBy指的是Car实体中定义的Owner的对象名;Car实体定义如下所示
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "owner_id")
private Owner owner;
这里的JoinColumn中的name对应Car表中外键关联的owner_id;如果不指定JoinColumn的话,默认就是实体的名称_主键,所以这里去掉之后也是可以的;
还有一种方式是建立中间关联表的方式,表结构如图
实体如下所示
@Table(name = "owner")
public class Owner implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@OneToMany
@JoinTable
(
name="OWNER_CARS",
joinColumns={ @JoinColumn(name="ownerid", referencedColumnName="id") },
inverseJoinColumns={ @JoinColumn(name="carid", referencedColumnName="id", unique=true) }
)
private Set<Car> cars = new HashSet<>();
这里的joinColumns指的连接的第一个表的信息,name指的关联表的列,referencedColumnName指的是对应实体的id;inverseJoinColumns指的是连接的第二个表的信息,name指的是关联表的列,referencedColumnName指的是列对应实体的id;
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@ManyToOne
@JsonIgnoreProperties("cars") //这里需要注意加上,不然会有问题的
private Owner owner;
2.OneToOne
假设1个车只有一个owner,一个owner只有一个车;
public class Owner implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@OneToOne
@JoinColumn(name = "owner_id")
private Owner owner;
这里的JoinColumn 中的name指的是Car表中关联的外键id;这样在获取Car信息的时候,就可以直接获取到owner的信息;
双向的oneToOne,entity如下所示
@Table(name = "car")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@OneToOne
@JoinColumn(name = "owner_id")
private Owner owner;
public class Owner implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@OneToOne(fetch=FetchType.LAZY, mappedBy="owner")
private Car car;
这里其中一个要指定mappedBy属性,标识Car实体中Owner属性的名称;这个接口返回如果都使用DTO后会有循环调用的问题,暂时没完美的解决办法;