使用spring jpa 如何给外键赋值
作者:客 卿
spring jpa 给外键赋值
最近在用spring data jap 的时候遇到一个问题,就是无法给一张表的外键赋予值,在A实体类中有一个属性的是另一个实体类B
如图
@JoinColumn的name指的是数据库表中的外键字段uid
这个外键在数据库中是vachar型的,但是在我的程序里却是一个实体类型的就是那个patient类
那么如果我们要在数据库表中添加一条数据,且还要为uid这个字段赋值的话,要怎么做呢?
如下图
这样就行了,这个问题困扰了我两三天,一开始也不是没想过用这种办法,而且实验了,但是失败了
失败的原因是因为@OneToOne注解被我设置了 cascade=CascadeType.PERSIST 这个属性,然后一运行就抛异常,不知道是什么原因 找了找网上的说法是 因为
"CascadeType.PERSIST只有A类新增时,会级联B对象新增。若B对象在数据库存(跟新)在则抛异常(让B变为持久态)"这个,但我也不是很理解这句话的意思。之所以写这篇博客是因为在网上找不到把这个问题说的很清楚的博客或者资料,希望其他新人能脱离这个坑。
以下是实体类chat
@Entity(name = "chat") public class chat { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") int id; @Lob @Basic(fetch = FetchType.LAZY) @Column(name = "msg", columnDefinition = "Text") String msg; @Lob @Basic(fetch = FetchType.LAZY) @Column(name = "hfmsg", columnDefinition = "Text") String hfmsg; @Column(name = "savetime") String savetime; @OneToOne @JoinColumn(name = "uid") patient patient; public int getId() { return id; } public patient getPatient() { return patient; } public void setPatient(patient patient) { this.patient = patient; } public void setId(int id) { this.id = id; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getHfmsg() { return hfmsg; } public void setHfmsg(String hfmsg) { this.hfmsg = hfmsg; } public String getSavetime() { return savetime; } public void setSavetime(String savetime) { this.savetime = savetime; } }
另一个实体类patient
@Entity(name="patient") public class patient { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") int id; @Column(name="uname") String uname; @Column(name="upass") String upass; @Column(name="tname") String tname; @Column(name="sex") String sex; @Column(name="age") String age; @Column(name="idcard") String idcard; @Column(name="tel") String tel; @Column(name="addr") String addr; @Column(name="delstatus") String delstatus; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public String getUpass() { return upass; } public void setUpass(String upass) { this.upass = upass; } public String getTname() { return tname; } public void setTname(String tname) { this.tname = tname; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getIdcard() { return idcard; } public void setIdcard(String idcard) { this.idcard = idcard; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } public String getDelstatus() { return delstatus; } public void setDelstatus(String delstatus) { this.delstatus = delstatus; } }
jpa外键关系映射(终极理解)
OneToOne
OneToOne是一对一关系,由一方的外键保存另一方的主键来维系双方的关系,而另一方需要获取关系映射而不需要维护外键即可获取对方,比如说Person和Address,由Person持有一个字段addr_id,保存Address的id,来维系双方的一对一关系
Person实体类如下:
@Entity @Table(name = "person") public class Person { @Id @Column(name = "id") private String id; @Column private String name; /** * 由person表持有addr_id,保存address表的id * referencedColumnName是指addr_id指定的address的映射字段,默认是id主键 */ @OneToOne @JoinColumn(name = "addr_id", referencedColumnName = "id") private Address address; }
双向OneToOne
如果关系由一方维系,而另一方又想获取维系方的数据,比如说Person和Address,关系由Person的addr_id表字段来维系,而在Address实体类中又想获取Person,此时就只需要一个关系映射即可,而不需要Address再搞个外键来维系Person关系
Address实体类如下:
@Entity @Table(name = "address") public class Address { @Id @Column(name = "id") private String id; @Column private String addrName; /** * 一对一的被维系方,指定由Person实体类中的address属性进行关系映射管理 * 从而获取Person数据 */ @OneToOne(mappedBy = "address") private Person person; }
单向OneToMany
OneToMany是一对多的关系,而一般来说外键是存储在多的一方,所以使用单向的OneToMany显得有点怪异,因为此时指定的外键是对方的表字段,比如说Department和Person是一对多,一个部门有多个人员,而两者之间的关系是由Person中的dept_id表字段保存Department中的id主键来维系的,此时在部门类中使用单向OneToMany映射一对多关系时,放的实际是Person表中的dept_id字段
Department实体类如下:
@Entity @Table(name = "department") public class Department { @Id @Column(name = "id") private String id; @Column private String deptName; /** * 单向一对多时,使用JoinColumn进行连接字段映射 * 此时name为对方也就是Person表中的外键dept_id字段, * 而映射的referencedColumnName是本表的主键id字段 */ @OneToMany @JoinColumn(name = "dept_id", referencedColumnName = "id") private List<Person> peopleList; }
OneToMany和ManyToOne双向
单向的OneToMany是有点怪异的,因为外键不是存在One一方的表中,所以在一对多时,建议使用OneToMany和ManyToOne配合使用,由Many方使用外键维系关系,而One方只需要指定Many方关系映射的属性即可。
多方使用ManyToOne维系关系,如:Person实体类
@Entity @Table(name = "person") public class Person { @Id @Column(name = "id") private String id; @Column private String name; /** * 多对一关系,由多方维系关系 * 通过person表的dept_id字段和department表的id主键字段做关系映射 */ @ManyToOne @JoinColumn(name = "dept_id") private Department department; }
少方使用OneToMany,获取映射,如:Department实体类
@Entity @Table(name = "department") public class Department { @Id @Column(name = "id") private String id; @Column private String deptName; /** * OneToMany和ManyToOne配合使用时,由ManyToOne多方进行关系管理 * 此时只需要指定管理映射属性,为Person中的department属性 */ @OneToMany(mappedBy = "department") private List<Person> peopleList; }
ManyToMany
多对多的关系中,往往需要借助第三张表,而这第三张表可以由JPA自动生成,此时就需要借助@JoinTable来自动生成第三张表,进行外键的管理,而@JoinTable由那一方指定都是可以的,另一方无需指定
Person实体类如下:
@Entity @Table(name = "person") public class Person { @Id @Column(name = "id") private String id; @Column private String name; /** * 多对多,通过JoinTable生成第三方表,指定各自主键的存放列名 * joinColumns:将本表id,存储到第三方表,列名为per_id * inverseJoinColumns:将对方表id,存储到第三方表,列名为dept_id * 注意:此处存放到第三方表的列名,需要和对方的外键名称相一致 */ @ManyToMany @JoinTable( name = "pro_dept", // 自动生成的第三方表名,可省略 joinColumns = @JoinColumn(name = "per_id"), // 将本表id,存储到第三方表,列名为per_id inverseJoinColumns = @JoinColumn(name = "dept_id") // 将对方表id,存储到第三方表,列名为dept_id ) private List<Department> department; }
Department实体类如下:
@Entity @Table(name = "department") public class Department { @Id @Column(name = "id") private String id; @Column private String deptName; /** * 通过mappedBy表明由Person实体的department属性进行关系管理 */ @ManyToMany(mappedBy = "department") private List<Person> personList; }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。