Reputation: 39
I am trying to add a feature to my website where the teacher can see a summary of students who have completed goals that week. This is my controller method
public IActionResult WeeklyDetails()
{
var user = svc.GetUser(GetSignedInUserId());
var goals = svc.GetGoalsForTeacher(user.Id);
var mostRecentMonday = DateTime.Now.StartOfWeek(DayOfWeek.Monday);//get week start of most recent Monday morning
var weekEnd = mostRecentMonday.AddDays(7).AddSeconds(-1); //will return the end of the day on Sunday
var results = goals.Where(g => g.AchievedOn >= mostRecentMonday && g.AchievedOn <= weekEnd).ToList();
for (int i = 0; i < results.Count; i++)
{
//Get count of current element to before:
int count = results.Take(i + 1)
.Count(r => r.Student.Name == results[i].Student.Name);
results[i].Count = count;
}
var result = results.GroupBy(x => x.Id)
.Select(group => group.First()).ToList();
return View(result);
}
In my cshtml view page I call the details like this
@foreach(var item in Model)
{
<p>@item.Student.Name @item.Count</p>
}
However, I achieve this result
Emma 1
Emma 2
Sarah 1
This is because emma has two goals which are completed in the list I know, however I would prefer for Emma 2 to be the only result that is shown. Is there a way to choose Max and then the first? Maybe not, my apologies if this is unclear.
Upvotes: 0
Views: 35
Reputation: 1276
I don't know the definition of result, but I think you group by the primary key of result (x.Id). You use the original result list as model of your view. But you provide aggregated data, so I would create a clean type (can be done inside your controller class as nested class):
public class GoalSummary
{
public int StudentId {get;set;}
public string Firstname {get;set;}
public string Name {get;set;}
public int Goals {get;set;}
}
Then you can use grouping and projecting (select) to create this results:
var summary = goals
.Where(g => g.AchievedOn >= mostRecentMonday && g.AchievedOn <= weekEnd)
.GroupBy(g => new {g.Student.Id, g.Student.Firstname, g.Student.Name})
.Select(g => new GoalSummary
{
StudentId = g.Key.Id,
Firstname = g.Key.Firstname,
Name = g.Key.Name,
Goals = g.Count()
}).ToList();
return View(summary);
If you are familiar with SQL: We want StudentId, Firstname, Name and COUNT(*). So we have to group by Id, Firstname and Name.
In your View you can use your typed summary:
@model List<YourNamespace.Controllers.YourController.GoalSummary>
Upvotes: 1