Spring应用中创建Applicant关联CreditRating时触发Field 'id' doesn't have a default value错误求助
嘿,我之前也踩过这个坑,咱们来捋清楚问题出在哪,然后一步步解决它!
首先,咱们先分析下你遇到的错误:Field 'id' doesn't have a default value,这个错误本质是JPA尝试插入credit_rating表的时候,没法自动生成id值。结合你的代码,我梳理了几个可能的原因和对应的解决方案:
1. 先检查数据库表结构(最容易忽略的点)
你在CreditRating实体里用了@GeneratedValue(strategy = GenerationType.IDENTITY),这个策略是依赖数据库的自增主键功能的。所以首先要确认你的credit_rating表的id字段是不是真的设置成了自增:
- 比如MySQL里,字段得是
id BIGINT AUTO_INCREMENT PRIMARY KEY - 如果是PostgreSQL,得是
id SERIAL PRIMARY KEY或者id BIGSERIAL PRIMARY KEY
如果数据库表的id没有设置自增,哪怕JPA配置了IDENTITY策略,数据库也不知道怎么生成id,自然会报这个错。
2. 优化代码逻辑:利用JPA的级联保存(更推荐)
看你的代码,你手动调用了creditRatingService.create()去保存CreditRating,然后再把它设置给Applicant。但其实你的Applicant和CreditRating之间已经配置了@OneToOne(cascade = CascadeType.ALL),这个注解的作用就是当你保存/更新/删除Applicant的时候,会自动对关联的CreditRating执行相同的操作。
所以完全可以省去手动保存CreditRating的步骤,直接创建对象关联后保存Applicant就行,这样JPA会自动帮你处理CreditRating的id生成和持久化:
修改你的Applicant创建方法:
public Applicant create(ApplicantDTO applicantDTO) { Applicant applicant = ApplicantMapper.toEntity(applicantDTO); // 直接创建CreditRating对象,不用手动调用save CreditRating creditRating = new CreditRating(); creditRating.setCreditRating(getRandomCreditRating()); applicant.setCreditRating(creditRating); // 保存Applicant时,级联保存CreditRating return applicantRepository.save(applicant); }
这样既简化了代码,又避免了手动保存可能带来的事务或实体状态不一致的问题。
3. 如果一定要保留手动保存的逻辑(检查返回的实体状态)
如果你坚持要通过creditRatingService.create()来创建CreditRating,那要确保creditRatingRepository.save()返回的是已经持久化、带有生成id的实体。Spring Data JPA的save()方法默认会返回持久化后的对象,但如果你的自定义实现有问题,可能会返回没有id的对象。
另外,还要检查CreditRating实体的注解有没有写错:
- 确认
@Id和@GeneratedValue(strategy = GenerationType.IDENTITY)注解都正确加在id字段上 - 实体类的
@Entity注解有没有正确标注,表名有没有和数据库对应
最后再排查一个小细节
如果你的数据库是MySQL,要确保credit_rating表的引擎是InnoDB(现在MySQL默认是这个,但旧版本可能是MyISAM),因为MyISAM对自增主键的支持不如InnoDB稳定,也可能导致这个错误。
按照上面的步骤排查,应该就能解决这个问题啦!
内容的提问来源于stack exchange,提问作者Ege Coskun

