ASP.NET MVC 中的透视表






4.92/5 (45投票s)
ASP.NET MVC 中带有透视选项的表格/报表控件
引言
如今,以透视形式显示数据已成为报告的重要组成部分。当您拥有大量数据或者希望以逻辑分组/聚合的方式以列显示数据时,可以使用此扩展方法。本文旨在简化在表示层中拥有 IEnumerable<Model>
时的数据透视过程。
为了在 UI 中显示数据,还需要一个表格控件。因此,我创建了一个简单的表格控件,该控件从 IEnumerable<Model>
呈现 HTML。
背景
在我的文章简化的透视 DataTable之后,我收到了读者的许多电子邮件请求,他们也希望在 ASP.NET MVC 中透视数据。因此,我决定编写一篇关于在 ASP.NET MVC 中透视数据的单独文章。在我之前的文章中,我提供了许多示例来以不同的透视形式显示数据。为了使文章简单,并且由于时间不足,我没有在本文中提供许多示例。但是,这些示例可以很容易地以与前一篇文章中提供的方式相同的方式导出。将来,我可能会在本文中提供许多不同的透视选项。现在,请查看带有简单表格/报表控件的基本透视。
Using the Code
要使用该代码,您只需要添加对 ReportControl
程序集的引用。然后,您可以直接在视图中使用该代码,如下所示
@Model.ReportWithPivot("", "ShopName", "SellingPrice",
AggregateFunction.Sum, "ItemType", "ItemName")
请注意,您的模型应为 IEnumerable
或派生自 IEnumerable
。
工作原理
要了解与透视相关的工作原理,请参阅我之前的文章:简化的透视 DataTable。此外,ReportWithPivot
是 IEnumerable
对象的扩展方法,它将 RowField
、DataField
、聚合函数和 ColumnFields
作为参数,并返回一个 HTML 表格,其中数据根据指定的参数进行透视。
public static HtmlString ReportWithPivot<T>(this IEnumerable<T> source, string cssClass,
string rowField, string dataField, AggregateFunction aggregate, params string[] columnFields)
where T : class
{
DataTable dt = source.ToDataTable();
return dt.ReportWithPivot
(cssClass, rowField, dataField, aggregate, columnFields);
}
public static HtmlString ReportWithPivot(this DataTable source, string cssClass,
string rowField, string dataField, AggregateFunction aggregate, params string[] columnFields)
{
Pivot p = new Pivot(source);
DataTable dt = p.PivotData(rowField, dataField, aggregate, columnFields);
return dt.Report(cssClass, columnFields.Length,
dt.Columns.Cast<DataColumn>().Select(x => x.ColumnName).ToArray());
}
为了简化操作,可以使用以下步骤解释此方法的工作原理
- 调用扩展方法
ReportWithPivot
,该方法采用透视参数。 - 此方法首先将
IEnumerable
源转换为DataTable
,然后调用ReportWithPivot
方法的另一个重载,该重载采用DataTable
作为参数。为了透视源,我们首先将数据转换为DataTable
,因为通过将其拆分为不同的部分,可以很容易地动态操作DataTable
。 - 现在,它以与我之前的文章中说明的相同方式透视
DataTable
中存在的数据。我们在新的DataTable
中获取透视数据。 - 获得透视数据后,将调用另一个扩展方法以将数据呈现到 HTML 报表中。您可以下载本文随附的源代码,并查看
ReportEx
类中存在的“Report”扩展方法。
设置透视的标头
Pivot
表格的标头已由 ReportHelper
类中存在的 PivotHeader(this Table table, string separator, int pivotLevel)
函数设置。它首先在表格中添加标头行数,并根据透视级别和内容应用数据。然后,它检查并合并重复的单元格数据。
public static void PivotHeader(this Table table, string separator, int pivotLevel)
{
TableRow row = table.Rows[0];
if (row.TableSection == TableRowSection.TableHeader)
{
TableRow r = new TableRow();
var headers = row.Cells.Cast<tablecell>().Select(x => x.Text);
for (int i = 0; i < pivotLevel; i++)
{
r = new TableRow();
r.TableSection = TableRowSection.TableHeader;
foreach (var x in headers)
{
string headerText = GetNthText(x, i, separator);
if (r.Cells.Count > 0 && r.Cells[r.Cells.Count - 1].Text == headerText)
r.Cells[r.Cells.Count - 1].ColumnSpan++;
else
r.Cells.Add(new TableHeaderCell
{ Text = headerText, ColumnSpan = 1 });
}
table.Rows.AddAt(i, r);
}
}
table.Rows.Remove(row);
}
下图是透视报表和原始报表的屏幕截图
关注点
本文还提供了一个示例,说明如何创建一个简单的 Report
/Grid
扩展方法来从集合中呈现 HTML。对于初学者来说,其中的代码也可以作为关于如何使用反射来读取属性并从中获取值的示例。下面的代码演示了这一点
public static DataTable ToDataTable<t>(this IEnumerable<t> data)
{
//PropertyDescriptorCollection properties =
// TypeDescriptor.GetProperties(typeof(T));
PropertyInfo[] properties = typeof(T).GetProperties();
DataTable table = new DataTable();
foreach (PropertyInfo prop in properties)
table.Columns.Add(prop.Name,
Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyInfo prop in properties)
row[prop.Name] = prop.GetValue(item, null) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
未来考量
目前,仅添加了一个透视报表的基本示例。请继续关注本文,以查看有关透视的更多功能。
历史
- 2014 年 8 月 22 日:首次版本发布
- 2014 年 9 月 5 日:问题修复:标头列在多列透视中呈现不正确