使用AutoMapper映射多表至ViewModel时,NumberOfExpenses始终为0如何解决?
解决AutoMapper映射Category到CategoryViewModel的计数问题
我帮你排查下这个问题,你的AutoMapper配置和EF数据加载环节都有小疏漏,一步步来修正:
1. 先修正AutoMapper的映射表达式
你原来的MapFrom写法有语法错误,而且没正确完成计数逻辑。正确的配置需要遍历Category下的BankingAccountCategories集合,把每个关联的Expenses数量累加起来,有两种写法可选:
写法一:用Sum统计每个BankingAccountCategory下的Expenses数量
CreateMap<Category, CategoryViewModel>() .ForMember(dest => dest.NumberOfExpenses, opt => opt.MapFrom(cat => cat.BankingAccountCategories .Sum(bac => bac.Expenses.Count())));
写法二:用SelectMany扁平所有Expenses后再计数
CreateMap<Category, CategoryViewModel>() .ForMember(dest => dest.NumberOfExpenses, opt => opt.MapFrom(cat => cat.BankingAccountCategories .SelectMany(bac => bac.Expenses) .Count()));
2. 必须确保EF加载了关联的导航属性
这是很多人容易忽略的点!如果用Entity Framework查询Category时,没主动Include关联的BankingAccountCategories和Expenses,EF默认懒加载(如果没开的话)或者没触发加载,会导致内存里这些集合是空的,计数自然为0。
EF Core的正确查询方式(支持ThenInclude)
var categories = dbContext.Categories .Include(c => c.BankingAccountCategories) .ThenInclude(bac => bac.Expenses) .ToList(); var viewModels = _mapper.Map<List<CategoryViewModel>>(categories);
EF6及以前的写法(用字符串Include)
var categories = dbContext.Categories .Include("BankingAccountCategories.Expenses") .ToList();
为什么原来的配置无效?
- 你原代码里写了
cat => cat => BankingAccountCategory.Select(...),多了一层cat =>,属于语法错误,表达式根本没正确执行; - 就算修正语法,你也只是返回了一个集合的集合,没有做计数操作,AutoMapper没法把集合转成int类型的
NumberOfExpenses; - 最关键的:导航属性没加载,内存里的关联集合都是空的,统计出来肯定是0。
额外推荐:直接在数据库层面统计(性能更优)
如果数据量较大,在内存里统计所有Expenses会浪费性能,不如直接让EF生成和你目标SQL类似的查询,在数据库层面完成统计,直接投影成ViewModel:
var categoryViewModels = dbContext.Categories .Select(cat => new CategoryViewModel { Id = cat.Id, Title = cat.Title, Description = cat.Description, NumberOfExpenses = cat.BankingAccountCategories .Sum(bac => bac.Expenses.Count()) }) .ToList();
这种方式不需要依赖AutoMapper,性能更好,还能避免导航属性加载的问题。
内容的提问来源于stack exchange,提问作者Felix
相关产品推荐
相关产品推荐

