AutoMapper ProjectTo() can't construct protobuf RepeatedField<> property

Viewed 140

I have an gRPC application with EF core as ORM. AutoMapper's ProjectTo method is used to construct DTOs. But I get error when constructing collection properties. I prepared the following example:

Database entities:

public sealed class Horse
{
    public Guid Id { get; init; }
    public ICollection<Workout> Workouts { get; } = new HashSet<Workout>();
}
public sealed class Workout
{
    public Guid Id { get; init; }
}

Context:

public sealed class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
    public DbSet<Horse> Horse { get; private init; } = null!;
}

DTOs:

public sealed class HorseDto
{
    public Guid Id { get; init; }
    public RepeatedField<WorkoutDto> Workouts { get; init; } = new RepeatedField<WorkoutDto>();
}
public sealed class WorkoutDto
{
    public Guid Id { get; init; }
}

Mapping:

var mapperConfiguration =
                new MapperConfiguration(_ =>
                {
                    _.CreateMap<Horse, HorseDto>();
                    _.CreateMap<Workout, WorkoutDto>();
                });

When I do:

var horseDto = await context.Horse
                   .Where(_ => _.Workouts.Count > 0)
                   .ProjectTo<HorseDto>(mapperConfiguration)
                   .FirstAsync();

I get:

System.ArgumentException: Argument types do not match
   at System.Linq.Expressions.Expression.Bind(MemberInfo member, Expression expression)
   at AutoMapper.QueryableExtensions.Impl.EnumerableExpressionBinder.BindEnumerableExpression(IConfigurationProvider configuration, PropertyMap propertyMap, ExpressionRequest request, ExpressionResolutionResult result, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps)
   at AutoMapper.QueryableExtensions.Impl.EnumerableExpressionBinder.Build(IConfigurationProvider configuration, PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionRequest request, ExpressionResolutionResult result, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps)
   at AutoMapper.QueryableExtensions.ExpressionBuilder.<>c__DisplayClass10_0.<CreateMapExpressionCore>g__CreateMemberBinding|4(PropertyExpression propertyExpression, <>c__DisplayClass10_1& )
   at AutoMapper.QueryableExtensions.ExpressionBuilder.<>c__DisplayClass10_0.<CreateMapExpressionCore>g__CreateMemberBindings|1()
   at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpressionCore(ExpressionRequest request, Expression instanceParameter, IDictionary`2 typePairCount, TypeMap typeMap, LetPropertyMaps letPropertyMaps)
   at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpressionCore(ExpressionRequest request, Expression instanceParameter, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps, TypeMap& typeMap)
   at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps)
   at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request)
   at AutoMapper.Internal.LockingConcurrentDictionary`2.<>c__DisplayClass2_1.<.ctor>b__1()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at AutoMapper.Internal.LockingConcurrentDictionary`2.GetOrAdd(TKey key)
   at AutoMapper.QueryableExtensions.ExpressionBuilder.GetMapExpression(Type sourceType, Type destinationType, Object parameters, MemberInfo[] membersToExpand)
   at AutoMapper.QueryableExtensions.ProjectionExpression.ToCore(Type destinationType, Object parameters, IEnumerable`1 memberPathsToExpand)
   at AutoMapper.QueryableExtensions.ProjectionExpression.ToCore[TResult](Object parameters, IEnumerable`1 memberPathsToExpand)
   at AutoMapper.QueryableExtensions.ProjectionExpression.To[TResult](Object parameters, Expression`1[] membersToExpand)
   at AutoMapper.QueryableExtensions.Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Object parameters, Expression`1[] membersToExpand)
   at AutoMapper.QueryableExtensions.Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Expression`1[] membersToExpand)
   at RepeatedFieldExample.Sandbox.Run()

Everything works fine if I replace RepeatedField<> with IEnumerable<>.

Workable direct LINQ Select:

var horseDto = await ctx.Horse
                        .Where(h => h.Workouts.Count > 0)
                        .Select(h => new HorseDto()
                        {
                            Id = h.Id,
                            Workouts = new RepeatedField<WorkoutDto>()
                            {
                                h.Workouts.Select(w => new WorkoutDto() {Id = w.Id})
                            }
                        })
                        .FirstAsync();

AutoMapper version is 10.1.1

0 Answers
Related