焰尾迭 通过本文主要向大家介绍了马桶c的个人空间,c语言,欲情 c max,维生素c,crh2c等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
最近在做报表统计方面的需求,涉及到行转列报表。根据以往经验使用SQL可以比较容易完成,这次决定挑战一下直接通过代码方式完成行转列。期间遇到几个问题和用到的新知识这里整理记录一下。
阅读目录
- 问题介绍
- 动态Linq
- System.Linq.Dynamic其它用法
- 总结
问题介绍
以家庭月度费用为例,可以在[Name,Area,Month]三个维度上随意组合进行分组,三个维度中选择一个做为列显示。
/// <summary>
/// 家庭费用情况
/// </summary>
public class House
{
/// <summary>
/// 户主姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 所属行政区域
/// </summary>
public string Area { get; set; }
/// <summary>
/// 月份
/// </summary>
public string Month { get; set; }
/// <summary>
/// 电费金额
/// </summary>
public double DfMoney { get; set; }
/// <summary>
/// 水费金额
/// </summary>
public double SfMoney { get; set; }
/// <summary>
/// 燃气金额
/// </summary>
public double RqfMoney { get; set; }
}
</div>
| 户主-月明细报表 | ||||||
| 户主姓名 | 2016-01 | 2016-02 | ||||
|---|---|---|---|---|---|---|
| 电费 | 水费 | 燃气费 | 电费 | 水费 | 燃气费 | |
| 张三 | 240.9 | 30 | 25 | 167 | 24.5 | 17.9 |
| 李四 | 56.7 | 24.7 | 13.2 | 65.2 | 18.9 | 14.9 |
| 区域-月明细报表 | ||||||
| 户主姓名 | 2016-01 | 2016-02 | ||||
|---|---|---|---|---|---|---|
| 电费 | 水费 | 燃气费 | 电费 | 水费 | 燃气费 | |
| 江夏区 | 2240.9 | 330 | 425 | 5167 | 264.5 | 177.9 |
| 洪山区 | 576.7 | 264.7 | 173.2 | 665.2 | 108.9 | 184.9 |
| 区域月份-户明细报表 | |||||||
| 区域 | 月份 | 张三 | 李四 | ||||
|---|---|---|---|---|---|---|---|
| 燃气费 | 电费 | 水费 | 燃气费 | 电费 | 水费 | ||
| 江夏区 | 2016-01 | 2240.9 | 330 | 425 | 5167 | 264.5 | 177.9 |
| 洪山区 | 2016-01 | 576.7 | 264.7 | 173.2 | 665.2 | 108.9 | 184.9 |
| 江夏区 | 2016-02 | 3240.9 | 430 | 525 | 6167 | 364.5 | 277.9 |
| 洪山区 | 2016-02 | 676.7 | 364.7 | 273.2 | 765.2 | 208.9 | 284.9 |
现在后台查出来的数据是List<House>类型,前台传过来分组维度和动态列字段。
第1个表格前台传给后台参数
{DimensionList:['Name'],DynamicColumn:'Month'}
第2个表格前台传给后台参数
{DimensionList:['Area'],DynamicColumn:'Month'}
第3个表格前台传给后台参数
{DimensionList:['Area','Month'],DynamicColumn:'Name'}
问题描述清楚后,仔细分析后你就会发现这里的难题在于动态分组,也就是怎么根据前台传过来的多个维度对List进行分组。
动态Linq
下面使用System.Linq.Dynamic完成行转列功能,Nuget上搜索System.Linq.Dynamic即可下载该包。
代码进行了封装,实现了通用的List<T>行转列功能。
/// <summary>
/// 动态Linq方式实现行转列
/// </summary>
/// <param name="list">数据</param>
/// <param name="DimensionList">维度列</param>
/// <param name="DynamicColumn">动态列</param>
/// <returns>行转列后数据</returns>
private static List<dynamic> DynamicLinq<T>(List<T> list, List<string> DimensionList, string DynamicColumn, out List<string> AllDynamicColumn) where T : class
{
//获取所有动态列
var columnGroup = list.GroupBy(DynamicColumn, "new(it as Vm)") as IEnumerable<IGrouping<dynamic, dynamic>>;
List<string> AllColumnList = new List<string>();
foreach (var item in columnGroup)
{
if (!string.IsNullOrEmpty(item.Key))
{
AllColumnList.Add(item.Key);
}
}
AllDynamicColumn = AllColumnList;
var dictFunc = new Dictionary<string, Func<T, bool>>();
foreach (var column in AllColumnList)
{
var func = DynamicExpression.ParseLambda<T, bool>(string.Format("{0}==\"{1}\"", DynamicColumn, column)).Compile();
dictFunc[column] = func;
}
//获取实体所有属性
Dictionary<string, PropertyInfo> PropertyInfoDict = new Dictionary<string, PropertyInfo>();
Type type = typeof(T);
var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
//数值列
List<string> AllNumberField = new List<string>();
foreach (var item in propertyInfos)
{
PropertyInfoDict[item.Name] = item;
if (item.PropertyType == typeof(int) || item.PropertyType == typeof(double) || item.PropertyType == typeof(float))
{
AllNumberField.Add(item.Name);
}
}
//分组
var dataGroup = list.GroupBy(string.Format("new ({0})", string.Join(",", DimensionList)), "new(it as Vm)") as IEnumerable<IGrouping<dynamic, dynamic>>;
List<dynamic> listResult = new List<dynamic>();
IDictionary<string, object> itemObj = null;
T vm2 = default(T);
foreach (var group in dataGroup)
{
itemObj = new ExpandoObject();
var listVm = group.Select(e => e.Vm as T).ToList();
//维度列赋值
vm2 = listVm.FirstOrDefault();
foreach (var key in DimensionList)
{
itemObj[key] = PropertyInfoDict[key].GetValue(vm2);
}
foreach (var column in AllColumnList

