激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C# - C# List實現行轉列的通用方案

C# List實現行轉列的通用方案

2021-12-28 16:41焰尾迭 C#

本篇通過行轉列引出了System.Linq.Dynamic,并且介紹了過濾功能,具有很好的參考價值。下面跟著小編一起來看下吧

最近在做報表統計方面的需求,涉及到行轉列報表。根據以往經驗使用sql可以比較容易完成,這次決定挑戰一下直接通過代碼方式完成行轉列。期間遇到幾個問題和用到的新知識這里整理記錄一下。

閱讀目錄

  • 問題介紹
  • 動態linq
  • system.linq.dynamic其它用法
  • 總結

問題介紹

以家庭月度費用為例,可以在[name,area,month]三個維度上隨意組合進行分組,三個維度中選擇一個做為列顯示。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/// <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; }
 }

 

 

戶主-月明細報表
戶主姓名 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>行轉列功能。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/// <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)
 {
  vm2 = listvm.firstordefault(dictfunc[column]);
  if (vm2 != null)
  {
  foreach (string name in allnumberfield)
  {
  itemobj[name + column] = propertyinfodict[name].getvalue(vm2);
  }
  }
 }
 listresult.add(itemobj);
 }
 return listresult;
 }

C# List實現行轉列的通用方案

標紅部分使用了system.linq.dynamic動態分組功能,傳入字符串即可分組。使用了dynamic類型,關于dynamic介紹可以參考其它文章介紹哦。

system.linq.dynamic其它用法

上面行轉列代碼見識了system.linq.dynamic的強大,下面再介紹一下會在開發中用到的方法。

where過濾

list.where("name=@0", "張三")

C# List實現行轉列的通用方案

上面用到了參數化查詢,實現了查找姓名是張三的數據,通過這段代碼你或許感受不到它的好處。但是和entityframework結合起來就可以實現動態拼接sql的功能了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/// <summary>
 /// ef實體查詢封裝
 /// </summary>
 /// <typeparam name="t">實體類型</typeparam>
 /// <param name="query">iqueryable對象</param>
 /// <param name="gridparam">過濾條件</param>
 /// <returns>查詢結果</returns>
 public static efpaginationresult<t> pagequery<t>(this iqueryable<t> query, querycondition gridparam)
 {
 //查詢條件
 effilter filter = getparametersql<t>(gridparam);
 var query = query.where(filter.filter, filter.listargs.toarray());
 //查詢結果
 efpaginationresult<t> result = new efpaginationresult<t>();
 if (gridparam.ispagination)
 {
 int pagesize = gridparam.pagesize;
 int pageindex = gridparam.pageindex < 0 ? 0 : gridparam.pageindex;
 //獲取排序信息
 string sort = getsort(gridparam, typeof(t).fullname);
 result.data = query.orderby(sort).skip(pageindex * pagesize).take(pagesize).tolist<t>();
 if (gridparam.iscalctotal)
 {
  result.total = query.count();
  result.totalpage = convert.toint32(math.ceiling(result.total * 1.0 / pagesize));
 }
 else
 {
  result.total = result.data.count();
 }
 }
 else
 {
 result.data = query.tolist();
 result.total = result.data.count();
 }
 return result;
 }
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/// <summary>
 /// 通過查詢條件,獲取參數化查詢sql
 /// </summary>
 /// <param name="gridparam">過濾條件</param>
 /// <returns>過濾條件字符</returns>
 private static effilter getparametersql<t>(querycondition gridparam)
 {
 effilter result = new effilter();
 //參數值集合
 list<object> listargs = new list<object>();
 string filter = "1=1";
 #region "處理動態過濾條件"
 if (gridparam.filterlist != null && gridparam.filterlist.count > 0)
 {
 stringbuilder sb = new stringbuilder();
 int paramcount = 0;
 datetime datetime;
 //操作符
 string stroperator = string.empty;
 foreach (var item in gridparam.filterlist)
 {
  //字段名稱為空則跳過
  if (string.isnullorempty(item.fieldname))
  {
  continue;
  }
  //匹配枚舉,防止sql注入
  operator operatorenum = (operator)enum.parse(typeof(operator), item.operator, true);
 
  //跳過字段值為空的
  if (operatorenum != operator.null && operatorenum != operator.notnull && string.isnullorempty(item.fieldvalue))
  {
  continue;
  }
  stroperator = operatorenum.getdescription();
  if (item.ignorecase && !item.isdatetime)
  {
  //2016-07-19添加查詢時忽略大小寫比較
  item.fieldvalue = item.fieldvalue.tolower();
  item.fieldname = string.format("{0}.tolower()", item.fieldname);
  }
  switch (operatorenum)
  {
  //等于,不等于,小于,大于,小于等于,大于等于
  case operator.eq:
  case operator.ne:
  case operator.gt:
  case operator.ge:
  case operator.lt:
  case operator.le:
  if (item.isdatetime)
  {
  if (datetime.tryparse(item.fieldvalue, out datetime))
  {
   if (!item.fieldvalue.contains("00:00:00") && datetime.tostring("hh:mm:ss") == "00:00:00")
   {
   if (operatorenum == operator.le)
   {
   listargs.add(datetime.parse(datetime.tostring("yyyy-mm-dd") + " 23:59:59"));
   }
   else
   {
   listargs.add(datetime);
   }
   }
   else
   {
   listargs.add(datetime);
   }
   sb.appendformat(" and {0} {1} @{2}", item.fieldname, stroperator, paramcount);
  }
  }
  else
  {
  listargs.add(converttotype(item.fieldvalue, getproptype<t>(item.fieldname)));
  sb.appendformat(" and {0} {1} @{2}", item.fieldname, stroperator, paramcount);
  }
  paramcount++;
  break;
  case operator.like:
  case operator.notlike:
  case operator.llike:
  case operator.rlike:
  listargs.add(item.fieldvalue);
  if (operatorenum == operator.like)
  {
  sb.appendformat(" and {0}.contains(@{1})", item.fieldname, paramcount);
  }
  else if (operatorenum == operator.notlike)
  {
  sb.appendformat(" and !{0}.contains(@{1})", item.fieldname, paramcount);
  }
  else if (operatorenum == operator.llike)
  {
  sb.appendformat(" and {0}.endswith(@{1})", item.fieldname, paramcount);
  }
  else if (operatorenum == operator.rlike)
  {
  sb.appendformat(" and {0}.startswith(@{1})", item.fieldname, paramcount);
  }
  paramcount++;
  break;
  case operator.null:
  listargs.add(item.fieldvalue);
  sb.appendformat(" and {0}=null", item.fieldname);
  paramcount++;
  break;
  case operator.notnull:
  listargs.add(item.fieldvalue);
  sb.appendformat(" and {0}!=null", item.fieldname);
  paramcount++;
  break;
  case operator.in:
  sb.appendformat(" and (");
  foreach (var schar in item.fieldvalue.split(','))
  {
  listargs.add(schar);
  sb.appendformat("{0}=@{1} or ", item.fieldname, paramcount);
  paramcount++;
  }
  sb.remove(sb.length - 3, 3);
  sb.appendformat(" )");
  break;
  case operator.notin:
  sb.appendformat(" and (");
  foreach (var schar in item.fieldvalue.split(','))
  {
  listargs.add(schar);
  sb.appendformat("{0}!=@{1} and ", item.fieldname, paramcount);
  paramcount++;
  }
  sb.remove(sb.length - 3, 3);
  sb.appendformat(" )");
  break;
  }
  if (sb.tostring().length > 0)
  {
  filter = sb.tostring().substring(4, sb.length - 4);
  }
 }
 #endregion
 }
 result.filter = filter;
 result.listargs = listargs;
 return result;
 }

總結

本篇通過行轉列引出了system.linq.dynamic,并且介紹了過濾功能,其實它的用處還有很多,等待大家發掘。下面給出本文示例代碼:dynamiclinq

以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持服務器之家!

原文鏈接:http://www.cnblogs.com/yanweidie/p/6485957.html

延伸 · 閱讀

精彩推薦
  • C#深入解析C#中的交錯數組與隱式類型的數組

    深入解析C#中的交錯數組與隱式類型的數組

    這篇文章主要介紹了深入解析C#中的交錯數組與隱式類型的數組,隱式類型的數組通常與匿名類型以及對象初始值設定項和集合初始值設定項一起使用,需要的...

    C#教程網6172021-11-09
  • C#Unity3D實現虛擬按鈕控制人物移動效果

    Unity3D實現虛擬按鈕控制人物移動效果

    這篇文章主要為大家詳細介紹了Unity3D實現虛擬按鈕控制人物移動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一...

    shenqingyu060520232410972022-03-11
  • C#C#通過KD樹進行距離最近點的查找

    C#通過KD樹進行距離最近點的查找

    這篇文章主要為大家詳細介紹了C#通過KD樹進行距離最近點的查找,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    帆帆帆6112022-01-22
  • C#WPF 自定義雷達圖開發實例教程

    WPF 自定義雷達圖開發實例教程

    這篇文章主要介紹了WPF 自定義雷達圖開發實例教程,本文介紹的非常詳細,具有參考借鑒價值,需要的朋友可以參考下...

    WinterFish13112021-12-06
  • C#C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    這篇文章主要介紹了C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題,簡單描述了訪問者模式的定義并結合具體實例形式分析了C#使用訪問者模式解決長...

    GhostRider9502022-01-21
  • C#C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    這篇文章主要介紹了C# 實現對PPT文檔加密、解密及重置密碼的操作方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下...

    E-iceblue5012022-02-12
  • C#C#實現XML文件讀取

    C#實現XML文件讀取

    這篇文章主要為大家詳細介紹了C#實現XML文件讀取的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    Just_for_Myself6702022-02-22
  • C#C#裁剪,縮放,清晰度,水印處理操作示例

    C#裁剪,縮放,清晰度,水印處理操作示例

    這篇文章主要為大家詳細介紹了C#裁剪,縮放,清晰度,水印處理操作示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    吳 劍8332021-12-08
主站蜘蛛池模板: 最新91在线视频 | 久久99国产视频 | 性片网站 | 欧美视频一区二区三区四区 | 91av国产在线 | 欧美成人精品h版在线观看 国产一级淫片在线观看 | 成人午夜在线播放 | 91久久精品一二三区 | 在线天堂中文在线资源网 | 成人在线视频在线观看 | 今井夏帆av一区二区 | 日本一区二区视频在线 | 一级免费黄色免费片 | 国产成人精品免费视频大全最热 | 国产一区毛片 | 色视频在线 | 午夜视频国产 | 欧美老外a级毛片 | 91短视频版高清在线观看免费 | 91精品国产乱码久久久久久久久 | 免费a级黄色毛片 | 一级电影在线观看 | 日本在线一区二区 | 羞羞草视频 | 亚洲黑人在线观看 | 在线高清中文字幕 | 日本高清一级片 | 午夜精品久久久久久中宇 | 中文黄色一级片 | 国产精品野外av久久久 | 国产羞羞视频在线免费观看 | 免费激情网址 | 久久精品99久久久久久2456 | 精精国产xxxx视频在线播放7 | 天天干导航 | 成人国产精品齐天大性 | 中文在线观看www | 亚州精品在线视频 | 激情网站免费观看 | 成人毛片网站 | 天天夜干 |