0

I have the following api controller that returns a json representation of the query you see here:

public async Task<ActionResult<IEnumerable<CarDto>>> GetCarData(Guid carID)
{
    var carData = await (from cl in _context.CarList
                         join tl in _context.transmissionList
                             on cl.CId equals tl.CId
                         join to in _context.transmissionOptions
                             on tl.TId equals to.TId
                         where cl.CId == carID
                         select new CarDto
                         {
                             CarId = cl.CarId,
                             TransmissionId = tl.TId,
                             OptionId = to.OptionId,
                             GearId = to.GearId
                         })
                         .ToListAsync();
    return carData;
}

The returned json data looks like this:

[
    {
        "carId": "351a",
        "transmissionId": "ec7",
        "optionId": "a1",
        "gearId": "674532a"
    },
    {
        "carId": "351a",
        "transmissionId": "ec7",
        "optionId": "b7",
        "gearId": "5f9173f"
    },
    {
        "carId": "351a",
        "transmissionId": "ec7",
        "optionId": "c5",
        "gearId": "cf807"
    }
]

However, I'd like for it to be formatted such that there is a property called transmissionChoices that contains an array of the possible options.

Like this:

{
    "carId": "351a",
    "transmissionId": "ec7",
    "transmissionChoices": [
        {
            "optionId": "a1",
            "gearId": "674532a"
        },
        {
            "optionId": "b7",
            "gearId": "5f9173f"
        },
        {
            "optionId": "c5",
            "gearId": "cf807"
        }
    ]
}

Is there a way to get the controller to format it like that?

1 Answer 1

1

You can use the LINQ GroupBy method and then project the grouped results into the shape you want.

public async Task<ActionResult<IEnumerable<object>>> GetCarData(Guid carID)
{
    var carData = await (from cl in _context.CarList
                        join tl in _context.transmissionList
                            on cl.CId equals tl.CId
                        join to in _context.transmissionOptions
                            on tl.TId equals to.TId
                        where cl.CId == carID
                        select new
                        {
                            CarId = cl.CarId,
                            TransmissionId = tl.TId,
                            OptionId = to.OptionId,
                            GearId = to.GearId
                        })
                        .GroupBy(x => x.CarId)
                        .Select(g => new
                        {
                            CarId = g.First().CarId,
                            TransmissionId = g.First().TransmissionId,
                            TransmissionChoices = g.Select(x => new
                            {
                                OptionId = x.OptionId,
                                GearId = x.GearId
                            })
                        })
                        .ToListAsync();
    return carData;
}

Note that this is projecting the results into an anonymous type. Feel free to create a model that matches the schema you need and then use that model in the Select(...) projection.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi, thanks! So would this require 2 models? My original one, CarDto, and a new one? Or would it be best to combine the two? Thanks again!
It's up to you. There's no real reason to have a defined model for the first projection since that type is not exposed by your API. I would probably just change the shape of your CarDto class to match your intended output. You'll probably want to add a TransmissionChoiceDto or something for the nested collection of { optionId; gearId; }.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.