SpringBoot中JPA ManyToOne关联仅一行获外键值其余为null问题
问题:JPA多对一关联配置异常,BillMaster表外键feeId数据异常
SpringBoot项目配置JPA多对一关联后,BillMaster表仅一行数据的fee_id外键有值,其余行该字段为null,且有值行的fee_id与billId主键值完全相同,需修正多对一关联配置。
原实体类代码
BillMaster 实体类
package com.cts.BillManagement.Entities; import java.util.Date; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; @Entity @Table(name="billMaster") public class BillMaster { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="billId") private int billId; @Column(name="rideId") private int rideId; @Column(name="noOfkm") private int noOfkm; @Column(name="totalbill") private int totalbill; @Column(name="noOfOccupants") private int noOfOccupants; @Column(name="date") private Date date; @ManyToOne @JoinColumn(name="feeId") private Fees fee; @Column(name="costPerOccupant") private int costPerOccupant; public BillMaster(int billId, int rideId, int noOfkm, int totalbill, int noOfOccupants, Fees fee, int costPerOccupant) { super(); this.billId = billId; this.rideId = rideId; this.noOfkm = noOfkm; this.totalbill = totalbill; this.noOfOccupants = noOfOccupants; this.fee = fee; this.costPerOccupant = costPerOccupant; } }
Fees 实体类
package com.cts.BillManagement.Entities; import java.util.List; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import jakarta.transaction.Transactional; @Transactional @Entity @Table(name="fees") public class Fees { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="feeId") private int feeId; @Column(name="carType") private String carType; @Column(name="carName") private String carName; @Column(name="fuelType") private String fuelType; @Column(name="averageInKm") private int averageInKm; @Column(name="costOfFuel") private int costOfFuel; @Column(name="wearTearCost") private int wearTearCost; @Column(name="drivercharges") private int drivercharges; @Column(name="carPoolCommision") private int carPoolCommision; @OneToMany(cascade = CascadeType.ALL,mappedBy = "fee") private List<BillMaster> billMaster; public Fees(int feeId, String carType, String carName, String fuelType, int averageInKm, int costOfFuel, int wearTearCost, int drivercharges, int carPoolCommision) { super(); this.feeId = feeId; this.carType = carType; this.carName = carName; this.fuelType = fuelType; this.averageInKm = averageInKm; this.costOfFuel = costOfFuel; this.wearTearCost = wearTearCost; this.drivercharges = drivercharges; this.carPoolCommision = carPoolCommision; } }
问题原因及修复方案
1. 核心问题点
- 缺少无参构造函数:JPA必须通过反射实例化实体类,无参构造是硬性要求,缺失会导致属性赋值异常
- 主键构造参数错误:主键用
GenerationType.AUTO自增,却在构造函数中手动传入主键值,干扰JPA主键生成逻辑,导致外键被错误赋值为主键值 - 冗余注解:Fees实体类上的
@Transactional属于业务层注解,放在实体类无意义,应移除
修正后的实体类代码
BillMaster 修正版
package com.cts.BillManagement.Entities; import java.util.Date; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; @Entity @Table(name="billMaster") public class BillMaster { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) // 用IDENTITY明确自增策略,避免数据库差异 @Column(name="billId") private int billId; @Column(name="rideId") private int rideId; @Column(name="noOfkm") private int noOfkm; @Column(name="totalbill") private int totalbill; @Column(name="noOfOccupants") private int noOfOccupants; @Column(name="date") private Date date; @ManyToOne @JoinColumn(name="feeId", nullable = false) // 若外键必填,添加nullable=false约束 private Fees fee; @Column(name="costPerOccupant") private int costPerOccupant; // 无参构造函数(必须) public BillMaster() { super(); } // 全参构造函数(移除主键参数) public BillMaster(int rideId, int noOfkm, int totalbill, int noOfOccupants, Date date, Fees fee, int costPerOccupant) { super(); this.rideId = rideId; this.noOfkm = noOfkm; this.totalbill = totalbill; this.noOfOccupants = noOfOccupants; this.date = date; this.fee = fee; this.costPerOccupant = costPerOccupant; } // 必须添加Getter/Setter,JPA需要访问属性 public int getBillId() { return billId; } public void setBillId(int billId) { this.billId = billId; } public int getRideId() { return rideId; } public void setRideId(int rideId) { this.rideId = rideId; } public int getNoOfkm() { return noOfkm; } public void setNoOfkm(int noOfkm) { this.noOfkm = noOfkm; } public int getTotalbill() { return totalbill; } public void setTotalbill(int totalbill) { this.totalbill = totalbill; } public int getNoOfOccupants() { return noOfOccupants; } public void setNoOfOccupants(int noOfOccupants) { this.noOfOccupants = noOfOccupants; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public Fees getFee() { return fee; } public void setFee(Fees fee) { this.fee = fee; } public int getCostPerOccupant() { return costPerOccupant; } public void setCostPerOccupant(int costPerOccupant) { this.costPerOccupant = costPerOccupant; } }
Fees 修正版
package com.cts.BillManagement.Entities; import java.util.List; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; @Entity @Table(name="fees") public class Fees { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="feeId") private int feeId; @Column(name="carType") private String carType; @Column(name="carName") private String carName; @Column(name="fuelType") private String fuelType; @Column(name="averageInKm") private int averageInKm; @Column(name="costOfFuel") private int costOfFuel; @Column(name="wearTearCost") private int wearTearCost; @Column(name="drivercharges") private int drivercharges; @Column(name="carPoolCommision") private int carPoolCommision; @OneToMany(cascade = CascadeType.ALL, mappedBy = "fee") private List<BillMaster> billMaster; // 无参构造函数(必须) public Fees() { super(); } // 全参构造函数(移除主键参数) public Fees(String carType, String carName, String fuelType, int averageInKm, int costOfFuel, int wearTearCost, int drivercharges, int carPoolCommision) { super(); this.carType = carType; this.carName = carName; this.fuelType = fuelType; this.averageInKm = averageInKm; this.costOfFuel = costOfFuel; this.wearTearCost = wearTearCost; this.drivercharges = drivercharges; this.carPoolCommision = carPoolCommision; } // 必须添加Getter/Setter public int getFeeId() { return feeId; } public void setFeeId(int feeId) { this.feeId = feeId; } public String getCarType() { return carType; } public void setCarType(String carType) { this.carType = carType; } public String getCarName() { return carName; } public void setCarName(String carName) { this.carName = carName; } public String getFuelType() { return fuelType; } public void setFuelType(String fuelType) { this.fuelType = fuelType; } public int getAverageInKm() { return averageInKm; } public void setAverageInKm(int averageInKm) { this.averageInKm = averageInKm; } public int getCostOfFuel() { return costOfFuel; } public void setCostOfFuel(int costOfFuel) { this.costOfFuel = costOfFuel; } public int getWearTearCost() { return wearTearCost; } public void setWearTearCost(int wearTearCost) { this.wearTearCost = wearTearCost; } public int getDrivercharges() { return drivercharges; } public void setDrivercharges(int drivercharges) { this.drivercharges = drivercharges; } public int getCarPoolCommision() { return carPoolCommision; } public void setCarPoolCommision(int carPoolCommision) { this.carPoolCommision = carPoolCommision; } public List<BillMaster> getBillMaster() { return billMaster; } public void setBillMaster(List<BillMaster> billMaster) { this.billMaster = billMaster; } }
数据保存注意事项
保存BillMaster时,需确保关联的Fees已持久化:
- 先查询已存在的Fees对象:
Fees existingFee = feesRepository.findById(feeId).orElseThrow(() -> new RuntimeException("费用配置不存在"));
- 将查询到的Fees对象设置到BillMaster中,再执行保存:
BillMaster bill = new BillMaster(rideId, noOfkm, totalbill, noOfOccupants, date, existingFee, costPerOccupant); billMasterRepository.save(bill);
内容的提问来源于stack exchange,提问作者Sahil03
相关产品推荐
相关产品推荐

