ASP.NET Core MVC创建Contract时出现NullReferenceException求助
解决ASP.NET Core MVC创建Contract时的NullReferenceException问题
问题说明
在ASP.NET Core MVC项目中创建新Contract时触发NullReferenceException,报错出现在模型的返回方法中。需求是基于CarGroup的PreisTag(日单价)结合租赁时长计算总价,让Contract模型返回该总价并显示在ContractsController的列表中。
异常原因分析
出现空引用的核心原因有三个:
- 导航属性未加载:EF Core默认使用延迟加载,当Contract的
CarList、或CarList的CarGroup未被显式加载时,访问这些属性会返回null,触发异常。 - 循环引用导致的加载问题:Contract和CarList互相持有对方的引用,这种循环依赖会导致EF Core无法正确加载关联数据,也容易引发空引用。
- 未做null校验:在计算总价的方法中,直接访问
Contract.AbgabeDatum、CarGroup.PreisTag等属性,没有先判断这些对象是否为null。
修复方案
1. 调整总价计算逻辑到Contract模型
租赁时长是Contract的属性(AusleihDatum和AbgabeDatum),总价作为Contract的衍生属性,直接在Contract中计算更合理,同时避免循环依赖。
2. 增加null校验
在计算前先检查必要的关联对象是否为空,避免空引用异常。
3. 查询时显式加载导航属性
在ContractsController的查询方法中,使用Include和ThenInclude显式加载所有需要的关联数据,不要依赖延迟加载。
4. 移除CarList中不必要的Contract关联
删除CarList里的Contract相关属性,消除循环引用。
修改后的代码示例
Contract模型修改
public class Contract { public int Id { get; set; } public int CustomerId { get; set; } public Customer Customer { get; set; } public int CarListId{get;set;} public CarList CarList { get; set; } [DataType(DataType.Date)] public DateTime AusleihDatum{ get; set; } [DataType(DataType.Date)] public DateTime AbgabeDatum { get; set; } public int KilometerstandAnfang { get; set; } public int KilometerstandEnde { get; set; } public double GesamtPreis { get { // 校验必要对象是否为空 if (CarList == null || CarList.CarGroup == null) return 0; // 可根据需求改为抛出明确异常,比如throw new InvalidOperationException("关联数据未加载"); if (AbgabeDatum < AusleihDatum) throw new InvalidOperationException("归还日期早于租赁日期"); TimeSpan differenz = AbgabeDatum - AusleihDatum; int ausleihzeit = (int)differenz.TotalDays; // 确保至少按1天计算(当天归还的情况) ausleihzeit = Math.Max(ausleihzeit, 1); return ausleihzeit * CarList.CarGroup.PreisTag; } } }
CarList模型修改
namespace MvcCar2.Models { public class CarList { public int Id { get; set; } public string Hersteller { get; set; } public string Modell { get; set; } public string Kennzeichen { get; set; } public string Farbe { get; set; } public int Kilometerstand { get; set; } public int CarGroupId { get; set; } public CarGroup CarGroup { get; set; } // 移除不必要的Contract关联,消除循环引用 // [NotMapped] // public int ContractId { get; set; } // public Contract Contract { get; set; } // 移除原GesamtPreis方法,计算逻辑已移至Contract } }
ContractsController查询方法修改
在获取Contract列表时,显式加载关联的CarList和CarGroup:
public async Task<IActionResult> Index() { var contracts = _context.Contracts .Include(c => c.Customer) .Include(c => c.CarList) .ThenInclude(cl => cl.CarGroup) // 链式加载CarList的CarGroup .ToListAsync(); return View(await contracts); }
额外注意事项
- 创建Contract时,确保传入的
CarListId对应的CarList在数据库中存在,否则CarList属性会为null。 - 如果使用延迟加载,需确保DbContext在访问导航属性时仍处于激活状态,但显式加载更可靠,避免上下文释放后引发的空引用。
内容的提问来源于stack exchange,提问作者Miki
相关产品推荐
相关产品推荐

