如何在不对列进行硬编码的情况下在 LINQ 中转换数据

How to pivot data in LINQ without hard coding columns

我在 sql server 中有一个 table 像这样

CodeItemsRule Table 
CodeID  ItemID RuleID 
00009   D1      2   
00009   D2      2
00009   D3      1
00008   D1      3
00007   D3      1
00007   D4      1
00010   D3      2
00010   D1      1
00010   D2      1

我需要像这样在 LINQ 中转换这些数据。

CodeID  D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 D14
00007          1  1
00009   2   2  1

下面给出的是我的代码,但它没有将其转换为数据透视格式。

List<CodeItemsRule> _CodeItemRules = new CodeItemsRuleRepository.GetAll();
var _GroupResult = _CodeItemRules.GroupBy(g => g.CodeID).Select(g => new 
{
    CodeID = g.Key,
    ItemRulesList = g.ToDictionary(t => t.ItemID, t => t.RuleID)
}).ToList()

我通过修改 the link 中的详细信息为您简化了解决方案。

首先在静态class中创建一个扩展方法ToPivotTable:

public static class PivotClass
{
    public static DataTable ToPivotTable<T, TColumn, TRow, TData>(this IEnumerable<T> source,
  Func<T, TColumn> columnSelector,
  Expression<Func<T, TRow>> rowSelector,
  Func<IEnumerable<T>, TData> dataSelector)
    {
        DataTable table = new DataTable();
        var rowName = ((MemberExpression)rowSelector.Body).Member.Name;
        table.Columns.Add(new DataColumn(rowName));
        var columns = source.Select(columnSelector).Distinct();

        foreach (var column in columns)
            table.Columns.Add(new DataColumn(column.ToString()));

        var rows = source.GroupBy(rowSelector.Compile())
                         .Select(rowGroup => new
                         {
                             Key = rowGroup.Key,
                             Values = columns.GroupJoin(
                                 rowGroup,
                                 c => c,
                                 r => columnSelector(r),
                                 (c, columnGroup) => dataSelector(columnGroup))
                         });

        foreach (var row in rows)
        {
            var dataRow = table.NewRow();
            var items = row.Values.Cast<object>().ToList();
            items.Insert(0, row.Key);
            dataRow.ItemArray = items.ToArray();
            table.Rows.Add(dataRow);
        }

        return table;
    }
}

然后,使用列表中的此扩展方法来获取您的枢轴 DataTable,如下所述:

List<CodeItemsRule> _CodeItemRules = new List<CodeItemsRule>()
{
    new CodeItemsRule()
    {
        CodeID="00009",
        ItemID="D1",
        RuleID=2
    },new CodeItemsRule()
    {
        CodeID="00009",
        ItemID="D2",
        RuleID=2
    },new CodeItemsRule()
    {
        CodeID="00009",
        ItemID="D3",
        RuleID=1
    },new CodeItemsRule()
    {
        CodeID="00008",
        ItemID="D1",
        RuleID=3
    },new CodeItemsRule()
    {
        CodeID="00007",
        ItemID="D3",
        RuleID=1
    },new CodeItemsRule()
    {
        CodeID="00007",
        ItemID="D4",
        RuleID=1
    },new CodeItemsRule()
    {
        CodeID="00010",
        ItemID="D3",
        RuleID=2
    },new CodeItemsRule()
    {
        CodeID="00010",
        ItemID="D1",
        RuleID=1
    },new CodeItemsRule()
    {
        CodeID="00010",
        ItemID="D2",
        RuleID=1
    }

};
var pivotTable = _CodeItemRules.ToPivotTable(
    item => item.ItemID,
    item => item.CodeID,
    items => items.Any() ? items.Sum(x => x.RuleID) : 0);