小伙伴被OneToMany映射折腾的够惨,楞是用不明白。主表ID主键并没有如愿以偿作为附表的外键,并且在保存主entity时还报错,说是附表的外键列不能为空…
我想,Hibernate不可能这么弱,肯定是用得不对。一顿搜索一顿琢磨,在MySQL数据库下,要这么做才行:
- 数据库层面,附表,即OneToMany的Many方在外键列上首先创建索引,然后添加外键,如下所示。一个job包含多个case,那么job_info就是主表,job_case就是附表。job_case附表里job_id列是外键,指向job_info主表的id列。
alter table job_case add index (jobId)
alter table job_case add foreign key (jobId) references job_info(id)
- 在主表的entity类里,添加List< JobCase >域,并且添加OneToMany注解和JoinColumn注解.
- 2.1 OneToMany注解,需要注意FetchType,如不注明采用Eager模式,就会走Lazy模式,这时entity类最好加上@Transactional注解,保持session,否则后面用到
List<JobCase>
会报错,没有transaction manager,无法连接DB查询关联的JobCase数据。 - 2.2 JoinColumn注解,name属性指的是附表外键列的列名(不是附表entity类的域名,是数据库里附表的外键列列名额)
- 2.3 JoinColumn注解,referencedColumnName指的是数据库主表作为附表外键的那个列名,同第一步里为附表建外键时references job_info(id)是一个道理
- 2.4 JoinColumn注解里nullable设为true
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name="jobId", referencedColumnName = "id", nullable = true)
private List<JobCase> caseList = new ArrayList<>();
- 在附表entity类的,外键列要设置成insertable = false, nullable = true,注意检查DB表对应列的设置,也是可为空才可以,这个设置非常关键…
@Column(name = "jobId", insertable = false, nullable = true)
private long jobId;
为什么附表的外键列设置成nullable才可以呢,不科学啊,外键一般不应该可以为空的呀…
我想了想,是这样的,一般MySQL数据库里,表的ID列在建表时都设置成了自增的,Hibernate在保存记录到数据库里时,它预先生成好的insert sql(OneToMany映射下,主表一条insert语句,附表0至多条insert语句)里是没办法写id值的,只能是在insert会后DB会给表的ID列写入一个自增值。我大胆猜测,Hibernate肯定是根据自己生成的Insert语句,先insert主表,再insert附表,最后去拿主表的id值,update到附表的外键里去。所以附表的外键列必须是insertable=false, nullable = true…
因吹斯汀!