如何用Linq将C#透视表数据转换为ViewModel并默认值为0?
问题
现有业务场景:数据库中的值表存储了不同职位层级(JobLevel)、性别(Gender)、颜色(Color)的员工数量数据,需按JobLevel进行透视后在DataGridControl中展示,且允许用户修改数值。需要先将数据库返回的EmployeeGroupValue数据转换为指定的EmployeeGroupValueViewModel对象,无对应数据时默认值为0。
枚举定义
public enum JobLevel { Top, Mid, Low } public enum Color { Red, Blue, Green } public enum Gender { Female, Male, Other }
值实体类
public class EmployeeGroupValue { [Key, Column(Order = 0)] [Required] public JobLevel JobLevel { get;set; } [Key, Column(Order = 1)] [Required] public Gender Gender { get;set; } [Key, Column(Order = 2)] [Required] public Color Color { get;set; } [Required] public int Value { get;set; } }
示例数据
| Id | JobLevel | Gender | Color | Value |
|---|---|---|---|---|
| 1 | Top | Male | Red | 10 |
| 2 | Top | Other | Red | 5 |
| 3 | Top | Female | Blue | 20 |
| 4 | Mid | Other | Blue | 5 |
| 5 | Mid | Female | Green | 50 |
| 6 | Low | Male | Green | 5 |
| 7 | Low | Other | Red | 7 |
| 8 | Low | Female | Green | 12 |
目标DataGrid展示样式
表头行1
| JobLevel | Female | Male | Other |
|---|
表头行2与数据行
| xxxxxxxxxxxx | R | B | G | R | B | G | R | B | G |
|---|---|---|---|---|---|---|---|---|---|
| Top | 0 | 20 | 0 | 10 | 0 | 0 | 5 | 0 | 0 |
| Mid | 0 | 0 | 50 | 0 | 0 | 0 | 0 | 5 | 0 |
| Low | 0 | 0 | 12 | 0 | 0 | 5 | 7 | 0 | 0 |
指定ViewModel
public class EmployeeGroupValueViewModel { public string JobLevel { get;set; } public int FemaleRed { get;set; } public int FemaleBlue { get;set; } public int FemaleGreen { get;set; } public int MaleRed { get;set; } public int MaleBlue { get;set; } public int MaleGreen { get;set; } public int OtherRed { get;set; } public int OtherBlue { get;set; } public int OtherGreen { get;set; } }
请问如何使用Linq实现上述数据转换,且无对应数据库行时默认值为0?
解决方案
可以通过Linq分组结合字典快速查找的方式实现,具体代码如下:
// 假设dbValues是从数据库查询得到的EmployeeGroupValue集合 var dbValues = new List<EmployeeGroupValue>(); // 替换为实际数据库查询结果 // 将原始数据转换为字典,键为(JobLevel, Gender, Color)的元组,便于快速取值 var valueLookup = dbValues.ToDictionary( item => (item.JobLevel, item.Gender, item.Color), item => item.Value ); // 生成所有职位层级对应的ViewModel,确保无数据时默认值为0 var viewModels = Enum.GetValues<JobLevel>() .Select(level => new EmployeeGroupValueViewModel { JobLevel = level.ToString(), // 女性各颜色对应值 FemaleRed = valueLookup.TryGetValue((level, Gender.Female, Color.Red), out int val) ? val : 0, FemaleBlue = valueLookup.TryGetValue((level, Gender.Female, Color.Blue), out val) ? val : 0, FemaleGreen = valueLookup.TryGetValue((level, Gender.Female, Color.Green), out val) ? val : 0, // 男性各颜色对应值 MaleRed = valueLookup.TryGetValue((level, Gender.Male, Color.Red), out val) ? val : 0, MaleBlue = valueLookup.TryGetValue((level, Gender.Male, Color.Blue), out val) ? val : 0, MaleGreen = valueLookup.TryGetValue((level, Gender.Male, Color.Green), out val) ? val : 0, // 其他性别各颜色对应值 OtherRed = valueLookup.TryGetValue((level, Gender.Other, Color.Red), out val) ? val : 0, OtherBlue = valueLookup.TryGetValue((level, Gender.Other, Color.Blue), out val) ? val : 0, OtherGreen = valueLookup.TryGetValue((level, Gender.Other, Color.Green), out val) ? val : 0 }) .ToList();
代码说明
- 字典转换:用
ToDictionary将原始数据转为元组键的字典,实现O(1)时间复杂度的查找,提升效率; - 遍历所有层级:通过
Enum.GetValues<JobLevel>()遍历所有职位层级,确保即使数据库中没有对应层级的数据,也能生成默认值为0的行; - 默认值处理:每个ViewModel属性通过
TryGetValue判断是否存在对应数据,不存在则赋值0,完全符合需求。
内容的提问来源于stack exchange,提问作者Donald N. Mafa
相关产品推荐
相关产品推荐

