Issue
In my Spring Boot project I have two models, Building and Location. I'm trying to create a new Location which belongs to a Building.
These are my models:
Location model
public class Location implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Getter
private Integer id;
@NonNull
@Getter
@Setter
private String name;
@NonNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "building_id")
@JsonBackReference("building-location")
@ToString.Exclude
@Getter
@Setter
private Building building;
@Getter
@Setter
@Version
@Column(name = "lock_version")
private Integer lockVersion;
}
Building model
public class Building implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Getter
private Integer id;
@NonNull
@Size(max = 10)
@Getter
@Setter
private String name;
@OneToMany(mappedBy = "building")
@JsonManagedReference("building-location")
@ToString.Exclude
@Getter
private List<Location> locations = new ArrayList<>();
@Getter
@Setter
@Version
@Column(name = "lock_version")
private Integer lockVersion;
}
This is my controller:
@PostMapping(value = "/")
@ResponseBody
public ResponseEntity<Response> createLocation(@Valid @RequestBody Location location) {
Location createdLocation = locationRepository.save(location);
return ResponseEntity.ok(
new Response(ResponseTypeEnum.Success, createdLocation)
);
}
This is the request body:
{
"name": "Kitchen",
"building": {
"id": 9
}
}
The problem I'm having is that JPA is not recognizing the Building object, so when I try to save the Location I get the following exception:
SQLException Column 'building_id' cannot be null. Query is: insert into location (building_id, lock_version, name) values (?, ?, ?), parameters [<null>,0,'Yoga Room']
.
If I get the building from DB using findById
and then set the Building property in the Location object it would work, but I don't want to fetch the object in order to save a Location instance. I just want to pass the foreign key and save the new instance.
Can I do that with JPA?
Solution
You cannot do that in JPA but one of the alternative solutions, if you do not want to hit the database for the Building entity, would be to load a reference instead:
Building b = buildingRepository.getOne(buildingId);
location.setBuilding(b);
Location createdLocation = locationRepository.save(location);
Remember that all needs to be within the same transaction.
getOne
javadoc:
Returns a reference to the entity with the given identifier.
Answered By - Maciej Kowalski