-1

I'm trying to use automapper to pull in a relationship's collection and convert to a dictionary, but I'm struggling with syntax. I have these two entities:

class Station {
  public int Id { get; set; }
  public string Name { get; set; }
}

class Client {
  public virtual ICollection<Station> Station { get; set; } = new List<Station>();
}

I want to write the results into a DTO:

class ClientDTO {
  public required IDictionary<string, int> Stations { get; init; }
}

Obviously there are other properties in all of them. I tried to use these maps:

CreateMap<ICollection<Station>, IDictionary<string, int>>()
    .ConstructUsing(stations => stations
        .Where(s => s.DeletedUtc == null)
        .ToDictionary(s => s.Name, s => s.Id));
    
CreateMap<Client, ClientDTO>()
    .ForMember(x => x.Stations, x => x.MapFrom(y => y.Station));

It's not able to create the projection though, and gets this exception:

System.InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.MethodCallExpression3' to type 'System.Linq.Expressions.NewExpression'.
at AutoMapper.QueryableExtensions.Impl.ProjectionBuilder.<>c__DisplayClass8_0.g__CreateDestination|3().
at AutoMapper.QueryableExtensions.Impl.ProjectionBuilder.CreateProjectionCore(ProjectionRequest request, Expression instanceParameter, TypeMap typeMap, LetPropertyMaps letPropertyMaps)

Is it possible to do this with a single projection, or do I need to load the ClientDTO without the stations, and then make a second query to pull in the stations and assign them? It's working like the below, I was just hoping there were a way to do it as a single call.

var clients = await context.Client
    .AsNoTracking()
    .Where(x => x.DeletedUtc == null)
    .OrderBy(x => x.Name)
    .ProjectTo<ClientDTO>(mapper.ConfigurationProvider)
    .ToArrayAsync(cancellationToken);

var stations = await context.Station
    .AsNoTracking()
    .Where(x => x.DeletedUtc == null)
    .GroupBy(x => x.ClientId)
    .ToDictionaryAsync(x => x.Key, x => x.ToDictionary(y => y.Name, y => y.Id), cancellationToken);

foreach (var client in clients)
    if (stations.TryGetValue(client.Id, out var dict))
        client.Stations = dict;
1
  • 1
    Try first without Automapper, you will be surprised. Commented Jul 10 at 7:49

0