ASP.NET Core MVC使用ViewModel报类型不匹配异常如何解决
异常原因
运行时抛出如下异常:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'SchoolProject.Models.Student', but this ViewDataDictionary instance requires a model item of type 'SchoolProject.ViewModels.StudentViewModel'.
触发的直接原因是类型不匹配:Details动作方法向视图传递的是SchoolProject.Models.Student类型的实体对象,但视图通过@model声明要求接收的模型类型为SchoolProject.ViewModels.StudentViewModel,两者类型不一致就会触发该错误。
正确实现方法
按照ViewModel的使用规范,你需要在动作方法中完成数据查询、ViewModel组装,再将组装好的实例传给视图,步骤如下:
- 修正
Details动作方法逻辑,替换为以下代码:
public async Task<IActionResult> Details(int id) { // 查询指定ID的学生信息 var student = await _context.Student.FirstOrDefaultAsync(m => m.StudentID == id); if (student == null) { return NotFound(); } // 查询该学生关联的所有课程(通过Enrollment中间表关联) var selectedCourses = await _context.Enrollment .Where(e => e.StudentID == id) .Select(e => e.Course) .ToListAsync(); // 组装StudentViewModel实例,填充视图所需的全部数据 var studentVm = new StudentViewModel { Student = student, Courses = selectedCourses }; // 将ViewModel实例传递给视图 return View(studentVm); }
- 清理视图冗余代码:视图顶部通过ViewData读取Courses的代码完全没有作用(后续逻辑都是从
Model.Courses取数据),可以直接删除:
@{ IEnumerable<Course> courses = ViewData["Courses"] as IEnumerable<Course>; }
关键说明
- ViewModel的核心作用是将单个视图需要的所有数据打包为一个强类型对象,一次性传递给视图,替代弱类型的ViewData/ViewBag传值方式,使用时必须保证 动作方法传入视图的对象类型和视图
@model声明的类型完全一致。 - 如果你希望在查询学生时一次性加载关联的选课数据,可以使用EF Core的关联加载写法,示例如下:
var student = await _context.Student .Include(s => s.Enrollments) .ThenInclude(e => e.Course) .FirstOrDefaultAsync(m => m.StudentID == id);
用这种写法拿到学生实体后,可直接通过student.Enrollments.Select(e => e.Course).ToList()获取关联课程列表,不需要单独写课程查询逻辑,两种查询方式效果一致,按需选择即可。
内容的提问来源于stack exchange,提问作者proz goret
相关产品推荐
相关产品推荐

