OneToMany:无法添加或更新子行:外键约束失败

OneToMany: Cannot add or update a child row: a foreign key constraint fails

有这些 类:

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);
    }
  }
}

spring 给出了 2 个关于外键的错误:

Error executing DDL "alter table vehicle drop foreign key FKk65fmqecth7bpxy163dwj685f" via JDBC Statement

然后

Cannot add or update a child row: a foreign key constraint fails (test_db.vehicle, CONSTRAINT FKk65fmqecth7bpxy163dwj685f FOREIGN KEY (vehicle_id) REFERENCES user_details (user_id))

我刚刚尝试更改 @OneToMany 关系上的 @JoinColumn 名称。如何解决?

PS: 我已经删除了之前创建的所有表,所以没有留下任何约束。

PPS: 使用 MySQL.

在您的设置中,您不应在 User class 中使用 @JoinColumn(name = "vehicleId")。请尝试以下操作(我假设不需要任何 User 中未引用的 Vehicle):

@Entity
@Data
@Table(name = "UserDetails")
public class User {
    @Id
    private int userId;
    
    private String userName;
    
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    private Collection<Vehicle> vehicles = new ArrayList<>();
}

单向关系是故意的吗?

问题出在用户实体的@JoinColumn(name = "vehicleId") 定义上:

@OneToMany
@JoinColumn(name = "vehicleId")
private Collection<Vehicle> vehicles = new ArrayList<>();

这告诉 JPA 在 Vehicle table 中创建和使用一个 'vehicleId' 列来引用用户实体。您的车辆 entity/table 虽然已经定义了一个 'vehicleId',这会导致错误和冲突 - 特别是当一个用户引用两辆车时,这可能会尝试让它们使用相同的 vehicleId 值。

尝试:

@OneToMany
@JoinColumn(name = "USER_ID")
private Collection<Vehicle> vehicles = new ArrayList<>();

相反,这将在车辆中创建一个 'userId' 列,以标识可以在此类映射中与车辆相关联的一个(且唯一一个)用户。这通常使用

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;
}

或者按照建议,您可以不使用 joinColumn。这将为此关系创建一个连接 table,它看起来很像多对多关系,但对关系 table.

有限制