RestController保存实体失败求助:手动创建实体为何可正常保存?
Let's break down the key differences between your two scenarios and fix the issue:
1. The Critical Missing Annotation: @RequestBody
The biggest problem here is that your REST controller method doesn't use the @RequestBody annotation on the Flow parameter.
When you send a JSON POST request, Spring needs explicit instructions to deserialize the request body into your Flow object. Without @RequestBody, Spring will try to populate the Flow using request parameters (like form data or query params) instead of the JSON body. That means the steps list in your Flow object is actually null or empty when you call flowRepository.save(flow)—even though you included steps in your JSON.
In contrast, your manual test explicitly creates Step instances, adds them to the Flow's steps list, and saves that fully populated object. JPA then cascades the persist operation to the steps (thanks to CascadeType.ALL), so they get saved to the database.
Fix for This Issue
Add @RequestBody to your controller method parameter:
@PostMapping("/new") public ResponseEntity insertFlow(@RequestBody Flow flow) { // Your existing code to set the user and save }
2. Secondary: Entity State and Id Handling
Even if you fix the @RequestBody issue, there's a subtle difference between your deserialized Step objects and the ones you create manually:
- In your JSON request, you explicitly set
"id": 0for each Step. - In your manual code, the Step's id defaults to 0 (since it's a primitive
long), but you don't set it explicitly.
For JPA entities using GenerationType.IDENTITY, the database generates the id when the entity is persisted. Primitive long ids default to 0, which can sometimes confuse JPA—does 0 mean a new entity, or an existing one with id 0? Most databases start auto-incrementing ids at 1, so 0 isn't a valid existing id, but JPA doesn't know that by default.
A Better Practice for Ids
Change your id fields from primitive long to nullable Long:
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // instead of long
This way, a null id clearly signals to JPA that the entity is new and needs to be persisted. When deserializing from JSON, if you omit the "id" field (or set it to null), Jackson will leave the id as null, making JPA's job easier.
Recap of the Two Scenarios
| Manual Creation | REST Controller (Original) |
|---|---|
Flow is fully populated with Step instances | Flow has empty/null steps (JSON body not parsed) |
JPA cascades persist to steps via CascadeType.ALL | No steps to persist |
| Step ids default to 0 (primitive long) | Step ids explicitly set to 0 via JSON (but this is irrelevant if steps aren't populated) |
Once you add @RequestBody, your JSON steps will be mapped to the Flow object, and JPA will persist them just like in your manual test.
内容的提问来源于stack exchange,提问作者user1007522

