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

ASP.NET Core MVC实现数据计算并插入SQL数据库的方法及问题解决

ASP.NET Core MVC 燃油数据计算与入库的高效实现方案

现有代码的核心问题

  • 累计值范围错误:当前Sum()没有过滤车辆,会把全表所有车辆的数据加总,完全不符合单车辆累计的需求。
  • 空值/除零异常:除法运算前未判断除数是否为0或null,比如accLitres为0时,consumptionKm = accKilometeres / accLitres直接报错;fuelPrice为0或null时,costOfTheKm也会出问题。
  • 重复查询数据库:多次调用fuelDbContext.FuelData会触发多次SQL查询,效率极低。
  • 未持久化数据:修改完fuel对象后没调用SaveChangesAsync(),数据根本不会写入数据库。
  • 方法不符合规范:实现了IActionResult但无返回值,违反MVC控制器方法要求。

高效实现思路

  1. 限定查询范围:只查询当前车辆的燃油记录,避免全表扫描。
  2. 内存中批量计算:一次性加载当前车辆的所有数据到内存后计算,减少数据库交互次数。
  3. 添加异常防护:除法运算前先校验除数合法性,避免空值/除零错误。
  4. 分离计算逻辑:把计算逻辑抽离到独立服务类,让控制器更简洁,同时方便复用和测试。
  5. 全程异步操作:使用EF Core异步方法提升并发性能。

优化后的代码实现

1. 控制器方法

[HttpPost]
public async Task<IActionResult> Calculate(FuelCalculationDataModel calcFuelDataRequest)
{
    // 基础参数校验
    if (string.IsNullOrEmpty(calcFuelDataRequest.vehicleregistrationNumber))
    {
        return BadRequest("车辆注册号不能为空");
    }

    // 一次性获取当前车辆的所有燃油记录
    var currentVehicleRecords = await fuelDbContext.FuelData
        .Where(p => p.vehicleregistrationNumber == calcFuelDataRequest.vehicleregistrationNumber)
        .ToListAsync();

    if (!currentVehicleRecords.Any())
    {
        return NotFound("未找到该车辆的燃油记录");
    }

    // 匹配要更新的目标记录(请根据业务调整匹配条件,比如ID)
    var targetFuelRecord = currentVehicleRecords.FirstOrDefault(p => /* 你的匹配逻辑,比如p.Id == calcFuelDataRequest.Id */);
    if (targetFuelRecord == null)
    {
        return NotFound("未找到要更新的燃油记录");
    }

    // 计算单车辆累计值
    var totalKilometers = currentVehicleRecords.Sum(p => p.odometerTotal ?? 0);
    var totalLitres = currentVehicleRecords.Sum(p => p.filledVolume ?? 0);

    // 计算单条记录的加油成本
    targetFuelRecord.refillCost = (targetFuelRecord.fuelPrice ?? 0) * (targetFuelRecord.filledVolume ?? 0);

    // 计算油耗(处理除零情况)
    targetFuelRecord.consumptionKm = totalLitres != 0 ? totalKilometers / totalLitres : 0;
    targetFuelRecord.consumptionLitres = totalKilometers != 0 ? totalLitres / totalKilometers : 0;

    // 计算每公里成本(处理油价为0的情况)
    targetFuelRecord.costOfTheKm = (targetFuelRecord.fuelPrice ?? 0) != 0 ? (1 / targetFuelRecord.fuelPrice.Value) * targetFuelRecord.consumptionKm : 0;

    // 计算总累计值(根据业务需求调整)
    targetFuelRecord.accLitresTotal = currentVehicleRecords.Sum(p => p.accLitres ?? 0);
    targetFuelRecord.accKilometerTotal = currentVehicleRecords.Sum(p => p.accKilometeres ?? 0);
    targetFuelRecord.consumptionKmTotal = currentVehicleRecords.Sum(p => p.consumptionKm ?? 0);
    targetFuelRecord.consumptionlitresTotal = currentVehicleRecords.Sum(p => p.consumptionLitres ?? 0);

    // 保存更改到数据库
    await fuelDbContext.SaveChangesAsync();

    return Ok("计算与数据更新完成");
}

2. 抽离计算逻辑到服务类(可选但推荐)

public class FuelCalculationService
{
    // 计算单车辆里程与油量累计值
    public (decimal TotalKilometers, decimal TotalLitres) CalculateAccumulatedValues(List<FuelData> vehicleRecords)
    {
        var totalKilometers = vehicleRecords.Sum(p => p.odometerTotal ?? 0);
        var totalLitres = vehicleRecords.Sum(p => p.filledVolume ?? 0);
        return (totalKilometers, totalLitres);
    }

    // 计算单次加油成本
    public decimal CalculateRefillCost(decimal? fuelPrice, decimal? filledVolume)
    {
        return (fuelPrice ?? 0) * (filledVolume ?? 0);
    }

    // 计算油耗
    public (decimal ConsumptionKm, decimal ConsumptionLitres) CalculateFuelConsumption(decimal totalKilometers, decimal totalLitres)
    {
        var consumptionKm = totalLitres != 0 ? totalKilometers / totalLitres : 0;
        var consumptionLitres = totalKilometers != 0 ? totalLitres / totalKilometers : 0;
        return (consumptionKm, consumptionLitres);
    }

    // 计算每公里成本
    public decimal CalculateCostPerKm(decimal? fuelPrice, decimal consumptionKm)
    {
        return (fuelPrice ?? 0) != 0 ? (1 / fuelPrice.Value) * consumptionKm : 0;
    }

    // 计算总累计值
    public (decimal AccLitresTotal, decimal AccKilometerTotal, decimal ConsumptionKmTotal, decimal ConsumptionLitresTotal) CalculateTotalAccumulated(List<FuelData> vehicleRecords)
    {
        var accLitresTotal = vehicleRecords.Sum(p => p.accLitres ?? 0);
        var accKilometerTotal = vehicleRecords.Sum(p => p.accKilometeres ?? 0);
        var consumptionKmTotal = vehicleRecords.Sum(p => p.consumptionKm ?? 0);
        var consumptionLitresTotal = vehicleRecords.Sum(p => p.consumptionLitres ?? 0);
        return (accLitresTotal, accKilometerTotal, consumptionKmTotal, consumptionLitresTotal);
    }
}

3. 控制器注入服务后的简化写法

private readonly FuelDbContext _fuelDbContext;
private readonly FuelCalculationService _calculationService;

// 构造函数注入
public YourController(FuelDbContext fuelDbContext, FuelCalculationService calculationService)
{
    _fuelDbContext = fuelDbContext;
    _calculationService = calculationService;
}

[HttpPost]
public async Task<IActionResult> Calculate(FuelCalculationDataModel calcFuelDataRequest)
{
    if (string.IsNullOrEmpty(calcFuelDataRequest.vehicleregistrationNumber))
    {
        return BadRequest("车辆注册号不能为空");
    }

    var currentVehicleRecords = await _fuelDbContext.FuelData
        .Where(p => p.vehicleregistrationNumber == calcFuelDataRequest.vehicleregistrationNumber)
        .ToListAsync();

    if (!currentVehicleRecords.Any())
    {
        return NotFound("未找到该车辆的燃油记录");
    }

    var targetFuelRecord = currentVehicleRecords.FirstOrDefault(p => /* 你的匹配逻辑 */);
    if (targetFuelRecord == null)
    {
        return NotFound("未找到要更新的燃油记录");
    }

    // 调用服务完成计算
    var (totalKilometers, totalLitres) = _calculationService.CalculateAccumulatedValues(currentVehicleRecords);
    targetFuelRecord.refillCost = _calculationService.CalculateRefillCost(targetFuelRecord.fuelPrice, targetFuelRecord.filledVolume);
    var (consumptionKm, consumptionLitres) = _calculationService.CalculateFuelConsumption(totalKilometers, totalLitres);
    targetFuelRecord.consumptionKm = consumptionKm;
    targetFuelRecord.consumptionLitres = consumptionLitres;
    targetFuelRecord.costOfTheKm = _calculationService.CalculateCostPerKm(targetFuelRecord.fuelPrice, consumptionKm);
    var (accLitresTotal, accKilometerTotal, consumptionKmTotal, consumptionLitresTotal) = _calculationService.CalculateTotalAccumulated(currentVehicleRecords);
    targetFuelRecord.accLitresTotal = accLitresTotal;
    targetFuelRecord.accKilometerTotal = accKilometerTotal;
    targetFuelRecord.consumptionKmTotal = consumptionKmTotal;
    targetFuelRecord.consumptionlitresTotal = consumptionLitresTotal;

    await _fuelDbContext.SaveChangesAsync();

    return Ok("计算与数据更新完成");
}

额外注意事项

  • 数据验证:给FuelCalculationDataModel添加数据注解(如[Required]、[Range])或使用FluentValidation,提前拦截无效输入。
  • 数据库优化:给vehicleregistrationNumber字段添加索引,提升查询效率。
  • 业务逻辑确认:如果accKilometeres应该是车辆的里程差总和(如本次加油里程减上次加油里程),请调整计算逻辑,不要直接累加所有odometerTotal。
  • 异常处理:添加try-catch块捕获数据库操作异常,返回更友好的错误提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 14:05:31