LINQ查询初始化ViewModel独立集合属性运行时报空如何解决
错误根因
你报错的核心原因是:将_db.Machinery.ToList()这类数据库查询操作写在了EF的IQueryable投影逻辑中,EF会尝试将这部分逻辑翻译为SQL语句执行,但数据库层面无法完成这种“给每条查询结果附加全量其他表数据”的操作,要么翻译直接失败抛出异常,要么每条结果都触发一次全表查询,引发性能问题和空引用异常。
方案1:保持现有List<DayTaskListViewModel>结构不变
如果你的业务确实需要每个DayTaskListViewModel实例都携带全量的两个集合,按以下步骤修改:
先提前把两个全量集合查询到内存,再给已查询出的列表批量赋值:
// 第一步:提前查询全局全量集合,仅执行1次数据库查询 var allMachinery = _db.Machinery.ToList(); var allCleaning = _db.Cleaning.ToList(); // 第二步:执行原有任务查询,不涉及两个集合的赋值 var model = (from a in _db.WorkTask.Where(y => y.TaskDate.Date == querytodaysDate.Date && y.IsActive == true && (y.IsPrivateUserName == null || y.IsPrivateUserName == currUserName)) join b in _db.WorkTaskLog.Where(x => (x.UserName == currUserName || x.UserName == null) && x.IsActive == true && x.StateStatusId < 4) on a.Id equals b.WorkTaskId into joinedT from c in joinedT.DefaultIfEmpty() select new DayTaskListViewModel { Id = a.Id, DateFormatted = a.DateFormatted, HasRegistrations = a.HasRegistrations, HasStartedRegistrations = a.HasStartedRegistrations, ItemName = a.ItemName, WorkTypeName = a.WorkTypeName, Description = a.Description, IsActive = c.IsActive ? c.IsActive : false, UserName = c.UserName ?? String.Empty, StateStatus = c.StateStatus ?? "Klar", WeekNumber = (int)currWeekNo, YearNumber = (int)currYearNo, Msg = "", TodaysDate = (DateTime)todaysDate, SignInUserName = currUserName, LocationName = a.LocationName, UnitCode = a.UnitCode }).ToList(); // 第三步:遍历内存列表,批量赋值集合属性 foreach (var taskItem in model) { taskItem.machineryList = allMachinery; taskItem.cleaningList = allCleaning; }
方案2:参考现有正常逻辑优化结构(更推荐)
你另一个控制器的写法逻辑是将主列表和全局集合拆分到外层ViewModel中,避免每条数据冗余存储相同的全量集合,性能更高,实现方式如下:
第一步:新增外层容器ViewModel
public class DayTaskListPageViewModel { // 原有的任务列表 public List<DayTaskListViewModel> TaskList { get; set; } // 全局独立集合 public IEnumerable<Machinery> machineryList { get; set; } public IEnumerable<Cleaning> cleaningList { get; set; } }
第二步:可选优化
如果不需要每个任务条目单独带集合,可以把DayTaskListViewModel里的machineryList和cleaningList属性删掉,减少冗余。
第三步:构造模型
// 查询任务列表 var taskList = (from a in _db.WorkTask.Where(y => y.TaskDate.Date == querytodaysDate.Date && y.IsActive == true && (y.IsPrivateUserName == null || y.IsPrivateUserName == currUserName)) join b in _db.WorkTaskLog.Where(x => (x.UserName == currUserName || x.UserName == null) && x.IsActive == true && x.StateStatusId < 4) on a.Id equals b.WorkTaskId into joinedT from c in joinedT.DefaultIfEmpty() select new DayTaskListViewModel { // 原有属性赋值不变,省略重复代码 Id = a.Id, // ...其余属性和之前一致 }).ToList(); // 构造外层模型,和你正常运行的写法逻辑完全一致 var model = new DayTaskListPageViewModel { TaskList = taskList, machineryList = await _db.Machinery.ToListAsync(), cleaningList = await _db.Cleaning.ToListAsync() };
第四步:视图适配
将视图绑定的模型类型改为DayTaskListPageViewModel,遍历Model.TaskList获取任务条目,直接通过Model.machineryList和Model.cleaningList调用全局集合即可。
内容的提问来源于stack exchange,提问作者René Wester
相关产品推荐
相关产品推荐

