Having these classes:
Vehicle.java:
@Data
@Entity
@NoArgsConstructor(force = true)
@RequiredArgsConstructor
public class Vehicle {
@Id
private final int vehicleId;
private final String vehicleName;
}
User.java:
@Entity
@Data
@Table(name = "UserDetails")
public class User {
@Id
private int userId;
private String userName;
@OneToMany
@JoinColumn(name = "vehicleId")
private Collection<Vehicle> vehicles = new ArrayList<>();
}
DemoApp.java:
@Bean
CommandLineRunner dataLoader3(VehicleRepository vehicleRepo, UserRepository userRepo){
return new CommandLineRunner() {
@Override
public void run(String... args) throws Exception {
Vehicle v = new Vehicle(0, "Car");
vehicleRepo.save(v);
Vehicle v2 = new Vehicle(1, "Bus");
vehicleRepo.save(v2);
User u = new User();
u.setUserName("First User");
u.setVehicles(Arrays.asList(v, v2));
userRepo.save(u);
}
}
}
The spring gives 2 errors regarding foreign key:
Error executing DDL "alter table vehicle drop foreign key FKk65fmqecth7bpxy163dwj685f" via JDBC Statement
and then
Cannot add or update a child row: a foreign key constraint fails (
test_db
.vehicle
, CONSTRAINTFKk65fmqecth7bpxy163dwj685f
FOREIGN KEY (vehicle_id
) REFERENCESuser_details
(user_id
))
I have just tried to change the @JoinColumn
name on @OneToMany
relation. How to solve this?
PS: I have deleted all created tables before so there are no constraints left.
PPS: using MySQL.
Problem is with the @JoinColumn(name = "vehicleId") definition on the User entity:
@OneToMany
@JoinColumn(name = "vehicleId")
private Collection<Vehicle> vehicles = new ArrayList<>();
This tells JPA to create and use a 'vehicleId' column within the Vehicle table to use to reference the User entity. Your Vehicle entity/table though already defines a 'vehicleId', which causes errors and conflicts - especially as one User is referencing two vehicles which is likely going to try to have them use the same value for the vehicleId.
Try:
@OneToMany
@JoinColumn(name = "USER_ID")
private Collection<Vehicle> vehicles = new ArrayList<>();
instead, which will create a 'userId' column within vehicle to identify the one (and only one) user that can be associated to the vehicle in this type of mapping. This is commonly done using
public class User {
@Id
private int userId;
private String userName;
@OneToMany(mappedBy="user")
private Collection<Vehicle> vehicles = new ArrayList<>();
}
public class Vehicle {
@Id
private final int vehicleId;
private final String vehicleName;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="USER_ID")
private User user;
}
Alternatively as was suggested, you can just leave off the joinColumn. This will create a join table for this relationship which will look much like a ManyToMany relationship, but with restrictions on the relation table.