Mapster - Mapping JOIN query results to DTO with nested collection

443 views Asked by At

I have an EF Core query that queries a set of SomeRecord entity and does an include on a List property like so :

return await _dbContext.Set<SomeRecord>()
    .AsNoTracking()
    .Include(r => r.ListOfSomeSubRecord)
    .ToListAsync();

This is just the problematic part of this query, there are a LOT more includes and conditions but all the other includes do not act on collections so they don't make the resultset grow in number of records returned.

The actual SQL EF Core generates is absolutely humongous and I decided to make a view to try and speed up this endpoint as well as encapsulate this query directly in SQL Server. The view returns one row per SomeSubRecord with the information of the associated SomeRecord repeating for each instance of the SomeSubRecord. With that in mind, I have made the following "entity" class that will map to this view :

public sealed class SomeRecord
{
    public Guid Id {get; set;}

    public string Name {get; set;}

    public Guid SomeSubRecordId {get; set;}

    public string SomeSubRecordName {get; set;}
}

Prior to me adding this, EF Core was perfectly happy mapping the result of its huge query to the original entity which contains a List as a property. That mapped nicely to my DTO using Mapster's Adapt method without me writing a single line of mapping, here is the DTO :

public sealed class SomeRecordResponse
{
    public Guid Id { get; set; }

    public string Name {get; set;}

    public IEnumerable<SomeSubRecordResponse> ListOfSomeSubRecords { get; set; }
}

Now I need to do this mapping myself, I need to convert this "exploded" dataset returned from my view into the response object Collection. I do not know how EF Core does this, neither do I know how to tell Mapster to do it.

2

There are 2 answers

1
Amir Tahan On

If you want to use mapster after all your query and before .TiLost or any thing use .ProjectTotype and then call your .ToList or anything... You can use select anyway but I don't suggest this way. Hope helpfull.

0
Svyatoslav Danyliv On

I would suggest to play with Select first. Eager loading query which you are tring to reproduce by View is hard to implement and maintain. Better to force EF Core to generate effective SQL query. Then think if you need Mapster here.

return await _dbContext.Set<SomeRecord>()
    .Select(r => new SomeRecordResponse
    {
        Id = r.Id,
        Name = r.Name,
        ListOfSomeSubRecords = r.ListOfSomeSubRecord.Select(s => new SomeSubRecordResponse
        {
            Id = s.Id,
            Name = s.Name
        })
    })
    .AsSplitQuery()
    .ToListAsync();

Also take a look at Mapster's ProjectToType which should generate similar Select automatically.