linq group by生成嵌套的POCO
linq group by to generate nested POCO
我连接了四个表以生成如下数据:
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 CORE 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 数据结构,以便从查询中编辑 return。如果我不使用 GroupBy,我可以生成一个简单的未嵌套 POCO,但我不想将响应数据作为单独的对象重复。这是一个 .NET 核心 web api 项目。
我觉得我很接近,但是 LINQ 中的 group by 让我失望了...
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()
更新:
在了解了 lINQ 中的多个 group By 之后,我的 .NET Core WEB API 仍然抱怨 bad request
而没有 return 嵌套 JSON。我确实使用装饰器将 LineItems 道具更新为 IDictionary 类型。有趣的是,如果我注释掉 LineItems 的 DTO 部分并将其设置为 null,响应会正常返回。你能帮忙看看这是什么问题吗?
public async Task<List<PointCardViewModel>> GetPointCards()
{
var queryPointCards =
((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,
dcob.PersonalAppearancePoints,
dcob.LunchPoints,
dcob.RecessOtherPoints,
dcob.AmHomeroomPoints,
dcob.PmHomeroomPoints
})
.GroupBy(x => new {
x.CardId,
x.StudentGrade,
x.StudentName,
x.CardDate,
x.PersonalAppearancePoints,
x.LunchPoints,
x.RecessOtherPoints,
x.AmHomeroomPoints,
x.PmHomeroomPoints
})
.Select(x => new PointCardViewModel
{
CardId = x.Key.CardId,
StudentName = x.Key.StudentName,
Grade = x.Key.StudentGrade,
EvaluationDate = x.Key.CardDate,
PersonalAppearancePoints = x.Key.PersonalAppearancePoints,
LunchPoints = x.Key.LunchPoints,
RecessOtherPoints = x.Key.RecessOtherPoints,
AMHomeRoomPoints = x.Key.AmHomeroomPoints,
PMHomeRoomPoints = x.Key.PmHomeroomPoints,
LineItems = null
//x.Select(c => new LineItemViewModel
//{
// ClassPeriod = c.ClassPeriod,
// ClassParticipationPoints = c.ClassParticipationPoints,
// AssignmentCompletionPoints = c.AssignmentCompletionPoints,
// BonusHomeworkPoints = c.BonusHomeworkPoints
//}).ToDictionary(key => key.ClassPeriod, value => (object)value)
}
)
).ToListAsync();
if (db != null)
{
return await queryPointCards;
}
return null;
}
您可以通过稍微更改查询和结果数据结构来实现此目的。例如
将您的数据结构更改为
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; }
}
请注意,LineItems
已转换为字典并用 JsonExtensionDataAttribute 修饰。
现在您可以将您的分组查询更改为
.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)
});
序列化结果数据将给出所需的 Json
如下更改Group by
和Select
:
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()
我连接了四个表以生成如下数据:
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 CORE 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 数据结构,以便从查询中编辑 return。如果我不使用 GroupBy,我可以生成一个简单的未嵌套 POCO,但我不想将响应数据作为单独的对象重复。这是一个 .NET 核心 web api 项目。 我觉得我很接近,但是 LINQ 中的 group by 让我失望了...
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()
更新:
在了解了 lINQ 中的多个 group By 之后,我的 .NET Core WEB API 仍然抱怨 bad request
而没有 return 嵌套 JSON。我确实使用装饰器将 LineItems 道具更新为 IDictionary 类型。有趣的是,如果我注释掉 LineItems 的 DTO 部分并将其设置为 null,响应会正常返回。你能帮忙看看这是什么问题吗?
public async Task<List<PointCardViewModel>> GetPointCards()
{
var queryPointCards =
((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,
dcob.PersonalAppearancePoints,
dcob.LunchPoints,
dcob.RecessOtherPoints,
dcob.AmHomeroomPoints,
dcob.PmHomeroomPoints
})
.GroupBy(x => new {
x.CardId,
x.StudentGrade,
x.StudentName,
x.CardDate,
x.PersonalAppearancePoints,
x.LunchPoints,
x.RecessOtherPoints,
x.AmHomeroomPoints,
x.PmHomeroomPoints
})
.Select(x => new PointCardViewModel
{
CardId = x.Key.CardId,
StudentName = x.Key.StudentName,
Grade = x.Key.StudentGrade,
EvaluationDate = x.Key.CardDate,
PersonalAppearancePoints = x.Key.PersonalAppearancePoints,
LunchPoints = x.Key.LunchPoints,
RecessOtherPoints = x.Key.RecessOtherPoints,
AMHomeRoomPoints = x.Key.AmHomeroomPoints,
PMHomeRoomPoints = x.Key.PmHomeroomPoints,
LineItems = null
//x.Select(c => new LineItemViewModel
//{
// ClassPeriod = c.ClassPeriod,
// ClassParticipationPoints = c.ClassParticipationPoints,
// AssignmentCompletionPoints = c.AssignmentCompletionPoints,
// BonusHomeworkPoints = c.BonusHomeworkPoints
//}).ToDictionary(key => key.ClassPeriod, value => (object)value)
}
)
).ToListAsync();
if (db != null)
{
return await queryPointCards;
}
return null;
}
您可以通过稍微更改查询和结果数据结构来实现此目的。例如
将您的数据结构更改为
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; }
}
请注意,LineItems
已转换为字典并用 JsonExtensionDataAttribute 修饰。
现在您可以将您的分组查询更改为
.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)
});
序列化结果数据将给出所需的 Json
如下更改Group by
和Select
:
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()