You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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已持久化:

  1. 先查询已存在的Fees对象:
Fees existingFee = feesRepository.findById(feeId).orElseThrow(() -> new RuntimeException("费用配置不存在"));
  1. 将查询到的Fees对象设置到BillMaster中,再执行保存:
BillMaster bill = new BillMaster(rideId, noOfkm, totalbill, noOfOccupants, date, existingFee, costPerOccupant);
billMasterRepository.save(bill);

内容的提问来源于stack exchange,提问作者Sahil03

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 06:37:01