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