Home > Software engineering >  LINQ with groupby and aggregate always shows default value
LINQ with groupby and aggregate always shows default value

Time:03-16

I have 2 model objects, DriverDetailsSourceObject which is meant to be for holding the DriverDetailsAPI response and DriverDetailsView which is used to show DriverDetails details with aggregated values on the web page.

public class DriverDetailsSourceObject
{
    public string Name { get; set; }
    public string GroupName { get; set; }
    public DateTime DateOfPurchase { get; set; }
}

public class DriverDetailsView
{
    public string Name { get; set; }
    public string GroupName { get; set; }
    public DateTime DateOfPurchase { get; set; }
    public int Count { get; set; } = 1;

    public DriverDetailsView(DriverDetailsSourceObject source)
    {
        Name = source.Name;
        GroupName = source.GroupName;
        DateOfPurchase = source.DateOfPurchase;
    }
}

DriverDetailsView is used on multiple pages. In 2 of them, Name, GroupName, DateOfPurchase and Count is shown where Count is always 1 and ToTalCount will be the number of DriverDetailsView objects in the collection.

Name Count Group Name Date
RoadAssistance A 1 Group A 1/1/2022
RoadAssistance A 1 Group B 2/1/2022
RoadAssistance A 1 Group A 2/2/2022
RoadAssistance B 1 Group A 2/2/2022
Total 4

In one of the pages, we need to show all the objects grouped by Name and calculate Count and list of GroupNames. I used the following LINQ expression.

private IEnumerable<DriverDetailsSourceObject> DriverDetails { get; set; } = Enumerable.Empty<DriverDetailsSourceObject>();
private IEnumerable<DriverDetailsView> DriverDetailsByOption { get; set; } = Enumerable.Empty<DriverDetailsView>();
.
.
DriverDetails = DriverService.GetDriverOptions(brandName, isAgentLoggedIn);

DriverDetailsByOption = DriverDetails.GroupBy(o => o.Name)
    .Select(d => 
        new DriverDetailsSourceObject()
        { 
            Name = d.First().Name,
            GroupName = d.First().GroupName,
            Count = d.Count()
        })
    .Select(v => new DriverDetailsView(v));

I am not getting the correct result using the above LINQ. Count is always 1 even after being grouped by Name. It could be because the Count has a default value 1 in DriverDetailsView, which I cannot change as it is used by other pages.

Name Count Group Name
RoadAssistance A 1 Group A
RoadAssistance B 1 Group A
Total 2

Expected result is given below:

Name Count Group Name
RoadAssistance A 3 Group A, Group B
RoadAssistance B 1 Group A
Total 4

How do I change my LINQ expression to get this result?

CodePudding user response:

Issue 1: As you didn't initialize the Count in DriverDetailsView's constructor, the Count will be 1 by default as initialized.

And meanwhile, you mention that the DriverDetailsSourceObject which is your API response class doesn't have the Count property.

Issue 2:

In your LINQ statement, you return the first GroupName instead of multiple GroupName:

GroupName = d.First().GroupName

Solution

For Issue 1: I would suggest using an empty constructor instead of the DriverDetailsView(DriverDetailsSourceObject source) constructor.

public class DriverDetailsView
{
    ...

    public DriverDetailsView() { }
    
    ...
}

For Issue 2:

To return multiple GroupName, you need to select and distinct GroupName, next use String.Join() to join the GroupName array as string.

Change the LINQ statement as below:

DriverDetailsByOption = DriverDetails.GroupBy(o => o.Name)
    .Select(d => new DriverDetailsView
    { 
        Name = d.Key,
        GroupName = String.Join(",", d.Select(x => x.GroupName).Distinct()),
        Count = d.Count()
    });

Sample program

As you .GroupBy() Name, this line

Name = d.First().Name

can be replaced with:

Name = d.Key
  • Related