从对象列表创建反向数据表

Create inversed datatable from object list

我的 ClassGrades table 具有以下字段:
Id, ClassId, Student, Match, Science, History, English

我使用如下函数检索所有正确的行:

IList<ClassGrade> classGrades = ClassService.GetClassGrades(classId: 1);

此列表中的 ClassGrade 对象如下所示:
Id=1,ClassId=1,学生='Mark',数学=50.6,科学=21.8,历史=70.7,英语=80.1
Id=2,ClassId=1,学生='Jacob',数学=70.8,科学=19.4,历史=78.7,英语=11.1
Id=3,ClassId=1,学生='Lauren',数学=21.9,科学=61.1,历史=99.5,英语=12.1
Id=4,ClassId=1,学生='Sarah',数学=81.7,科学=65.2,历史=73.7,英语=65.1

我需要翻转这些结果,使学生成为列,带成绩的科目成为行,然后将其绑定到我页面上的网格。 我认为创建一个新数据 table 并根据需要对其进行自定义是执行此操作的最佳方法。

DataTable dt = new DataTable();

最后我的网格需要看起来像这样:

            Mark    Jacob   Lauren   Sarah  
Math        50.6    70.8    21.9     81.7  
Science     21.8    19.4    61.1     65.2  
History     70.7    78.7    99.5     73.7  
English     80.1    11.1    12.1     65.1 

有人可以给我一个示例,说明我如何获取 ClassGrades 的对象列表并动态创建类似于上述内容的数据table。 我更愿意尽可能使用 linq。此外,如果在 sql 中完全执行此操作是首选方式,我也可以接受,但举个例子会很好。

有几点需要注意:

下面是我遇到问题的示例:

// retrieve object list
IList<ClassGrade> classGrades = ClassService.GetClassGrades(classId: 1);

// create datatable
DataTable dt = new DataTable();

// get list of students
var students = from s in classGrades
               select s.Student

// get list of subjects
IList<string> subjects = new List<string>() { "Math", "Science", "History", "English" };

// create columns
table.Columns.Add(subject, typeof(string));
foreach (var student in students)
{
    table.Columns.Add(student, typeof(double));
}

// create rows
foreach (var subject in subjects) 
{
    row = dt.NewRow();
    row[subject] = subject;

    foreach (var classGrade in classGrades)
    {
        // this is where I get stuck
        row[classGrade.Student] = 
    }
}

在 LinqPad 中测试。结果见附图。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace PivotDataTable
{
    class Program
    {
        public static object GetPropValue(object src, string propName)
        {
            return src.GetType().GetProperty(propName).GetValue(src, null);
        }

        static void Main()
        {
            // retrieve object list
            var classGrades = new List<ClassGrades>() {
                new ClassGrades() {Id=1, ClassId=1, Student="Mark", Math=50.6, Science=21.8, History=70.7, English=80.1},
                new ClassGrades() {Id=2, ClassId=1, Student="Jacob", Math=70.8, Science=19.4, History=78.7, English=11.1},
                new ClassGrades() {Id=3, ClassId=1, Student="Lauren", Math=21.9, Science=61.1, History=99.5, English=12.1},
                new ClassGrades() {Id=4, ClassId=1, Student="Sarah", Math=81.7, Science=65.2, History=73.7, English=65.1}
            };

            // create datatable
            DataTable dt = new DataTable();

            // get list of students
            var students = from s in classGrades
                select s.Student;

            // get list of subjects
            var subjects = new List<string>() { "Math", "Science", "History", "English" };

            // create columns
            dt.Columns.Add("subject", typeof(string));
            foreach (var student in students)
            {
                dt.Columns.Add(student, typeof(double));
            }

            // create rows
            foreach (var subject in subjects)
            {
                var row = dt.NewRow();
                row[0] = subject;

                foreach (var classGrade in classGrades)
                {
                    row[classGrade.Student] = Convert.ToDouble(GetPropValue(classGrade, subject));
                }

                // add row to data table
                dt.Rows.Add(row);
            }

            Console.Write("Press any key to continue . . . ");
            // to see the result in LinqPad: remark the ReadKey line, unremark the Dump line
            Console.ReadKey(true);
            //dt.Dump();
        }
    }

    class ClassGrades
    {
        public int Id { get; set; }
        public int ClassId { get; set; }
        public string Student { get; set; }
        public double Math { get; set; }
        public double Science { get; set; }
        public double History { get; set; }
        public double English { get; set; }
    }
}