C# 用于生成嵌套POCO的linq group by

C# 用于生成嵌套POCO的linq group by,c#,linq,lambda,group-by,igrouping,C#,Linq,Lambda,Group By,Igrouping,我将四个表连接起来以生成如下数据: Name Grade CardID Date Class Listen Read Write Jane Doe A 1001 2020-10-01 Period 1 - Spanish 500 500 500 John Doe B+ 1002 2010-10-02 Pereiod 2 - English 1000

我将四个表连接起来以生成如下数据:

Name        Grade   CardID   Date       Class               Listen  Read    Write
Jane Doe    A       1001    2020-10-01  Period 1 - Spanish  500     500     500  
John Doe    B+      1002    2010-10-02  Pereiod 2 - English 1000    1000    1000     
Jane Doe    A       1001    2020-10-01  Period 3 - Englsih  500     1000    1000    
如何使用LINQ group by将上述数据转换为如下所示的嵌套形式?这是一个.NET核心WEB API项目,使用来自LINQ查询数据的DTO对象投影

[
  {
    "cardId": 1001,
    "studentName": "Jane Doe",
    "grade": "A",
    "evaluationDate": "2020-10-01T00:00:00",
    "Period 1 - Spanish": {
      "Listen": 1000,
      "Read": 500,
      "Write": 500
    },
    "Period 3 - English": {
      "Listen": 1000,
      "Read": 500,
      "Write": 1000
    }
  },
  {
    "cardId": 1002,
    "studentName": "John Doe",
    "grade": "B+",
    "evaluationDate": "2010-10-01T00:00:00",
    "Period 2 - English": {
      "Listen": 500,
      "Read": 500,
      "Write": 1000
    }
  }
]
下面我有两个viewModel类,用于生成从查询返回的嵌套POCO数据结构。如果我不使用GroupBy,我可以生成一个简单的未列出的POCO,但我不想将响应数据作为单独的对象重复。这是一个.NET核心web api项目。 我觉得我很接近,但是林克的小组把我甩了

public class PointCardViewModel 
{
    public int CardId { get; set; }
    public string StudentName { get; set; }
    public string Grade { get; set; }
    public DateTime EvaluationDate { get; set; }
    public IEnumerable<LineItemViewModel> LineItems { get; set; }
}
public class LineItemViewModel
{
    public string ClassPeriod { get; set; }
    public int Listen { get; set; }
    public int Read { get; set; }
    public int Write { get; set; }
}
  ((from s in db.Students
  join dc in db.DailyCards on s.StudentId equals dc.StudentId
  join dcli in db.DailyCardLineItems on dc.CardId equals dcli.CardId
  join dcob in db.DailyCardOtherBehaviors on dc.CardId equals dcob.CardId
  select new
  {
      s.StudentName,
      s.StudentGrade,
      dc.CardId,
      dc.CardDate,
      dcli.ClassParticipationPoints,
      dcli.AssignmentCompletionPoints,
      dcli.BonusHomeworkPoints,
      dcli.ClassPeriod
  })
  .GroupBy(x => x.CardId)
  .Select(g => new PointCardViewModel()
  {
      CardId = g.Key,
      StudentName = g.Select(c => c.StudentName).First(),
      Grade = g.Select(c => c.StudentGrade).First(),
      EvaluationDate = x.CardDate,
      LineItems = g.Select(y => new LineItemViewModel()
                  {
                      //Class
                      //Read
                      //Listen
                      //Write
                  })
  }).toList()
                          

您可以通过稍微更改查询和结果数据结构来实现这一点。比如说

将数据结构更改为

public class PointCardViewModel 
{
    public int CardId { get; set; }
    public string StudentName { get; set; }
    public string Grade { get; set; }
    public DateTime EvaluationDate { get; set; }
    [JsonExtensionData]
    public IDictionary<string, object> LineItems { get; set; }  //Change Here
}
public class LineItemViewModel
{
    public string ClassPeriod { get; set; }
    public int Listen { get; set; }
    public int Read { get; set; }
    public int Write { get; set; }
}
序列化结果数据将得到所需的Json


通过更改
组,然后
选择
,如下所示:

var result=((from s in db.Students
  join dc in db.DailyCards on s.StudentId equals dc.StudentId
  join dcli in db.DailyCardLineItems on dc.CardId equals dcli.CardId
  join dcob in db.DailyCardOtherBehaviors on dc.CardId equals dcob.CardId
  select new
  {
      s.StudentName,
      s.StudentGrade,
      dc.CardId,
      dc.CardDate,
      dcli.ClassParticipationPoints,
      dcli.AssignmentCompletionPoints,
      dcli.BonusHomeworkPoints,
      dcli.ClassPeriod
  })
  .GroupBy(x => new { x.StudentName, x.CardId, x.StudentGrade, x.CardDate})
  .Select(g => new PointCardViewModel()
  {
      CardId =g.Key.CardId,
      StudentName = g.Key.StudentName,
      Grade = g.Key.StudentGrade,
      EvaluationDate = g.Key.CardDate,
      LineItems = g.Select(y => new LineItemViewModel
                  {
                      Class=y.Class,
                      Read=y.ClassParticipationPoints,
                      Listen=y.AssignmentCompletionPoints,
                      Write=y.BonusHomeworkPoints
                  })
  }).toList()

为什么要这样做,你有没有考虑过使用某种ORM?我面临的问题与这里完全相同:我希望有人知道如何解决这个问题,并从一开始就指导我的“我有四个表连接”,我想知道:为什么不直接查询这四个表,并获得你想要的数据结构?现在您首先将数据层次结构展平,然后再次尝试将其展平。@GertArnold我同意这可能会解决我的问题。但是,如果我已经有了这样一个平面视图,该怎么办呢。我的问题是,我不明白为什么
行项目的嵌套DTO投影会把一切都搞砸?我真的很感激这把小提琴,并帮助我解决groupby问题。但是我仍然没有让我的.NET核心WEB API方法返回正确的响应。请使用
get
方法查看我更新的问题。
.GroupBy(x=> new {x.Name,x.Grade,x.CardID,x.Date})
                .Select(x=> new PointCardViewModel
                        {
                            CardId=x.Key.CardID,
                            StudentName = x.Key.Name,
                            Grade = x.Key.Grade,
                            EvaluationDate = x.Key.Date,
                            LineItems = x.Select(c=> new LineItemViewModel
                            {
                                ClassPeriod = c.Class,
                                Listen = c.Listen,
                                Read = c.Read,
                                Write = c.Write
                                
                            }).ToDictionary(key=>key.ClassPeriod,value=>(object)value)
                        });
var result=((from s in db.Students
  join dc in db.DailyCards on s.StudentId equals dc.StudentId
  join dcli in db.DailyCardLineItems on dc.CardId equals dcli.CardId
  join dcob in db.DailyCardOtherBehaviors on dc.CardId equals dcob.CardId
  select new
  {
      s.StudentName,
      s.StudentGrade,
      dc.CardId,
      dc.CardDate,
      dcli.ClassParticipationPoints,
      dcli.AssignmentCompletionPoints,
      dcli.BonusHomeworkPoints,
      dcli.ClassPeriod
  })
  .GroupBy(x => new { x.StudentName, x.CardId, x.StudentGrade, x.CardDate})
  .Select(g => new PointCardViewModel()
  {
      CardId =g.Key.CardId,
      StudentName = g.Key.StudentName,
      Grade = g.Key.StudentGrade,
      EvaluationDate = g.Key.CardDate,
      LineItems = g.Select(y => new LineItemViewModel
                  {
                      Class=y.Class,
                      Read=y.ClassParticipationPoints,
                      Listen=y.AssignmentCompletionPoints,
                      Write=y.BonusHomeworkPoints
                  })
  }).toList()