Base solution for your next web application
Open Closed

Using GraphQL Without Automapper? #8700


User avatar
0
tusksoft created

We're experimenting with adding GraphQL into our project. We have created types for our complex objects, but now we're getting an error when trying to run the query in the playground. From the message, it appears that GraphQL expects automapper to map Dto to domain objects, however, we are mapping Dto with our own custom code, bypassing automapper.

Is it possbile to tell the GraphQL query to map using our own custom code, instead of automapper?

Here is the full error message/stack trace that comes on the query:

"GraphQL.ExecutionError: Error trying to resolve Entries.\r\n ---> System.InvalidOperationException: Missing map from MyProject.Domain.TimeTracking.TimeEntry to MyProject.Domain.Core.TimeEntries.Dto.TimeEntryDto. Create using CreateMap<TimeEntry, TimeEntryDto>.\r\n at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpressionCore(ExpressionRequest request, Expression instanceParameter, IDictionary2 typePairCount, LetPropertyMaps letPropertyMaps, TypeMap& typeMap)\r\n at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request, IDictionary2 typePairCount, LetPropertyMaps letPropertyMaps)\r\n at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request)\r\n at AutoMapper.LockingConcurrentDictionary2.<>c__DisplayClass2_1.<.ctor>b__1()\r\n at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode)\r\n at System.Lazy1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)\r\n at System.Lazy1.CreateValue()\r\n at AutoMapper.LockingConcurrentDictionary2.GetOrAdd(TKey key)\r\n at AutoMapper.QueryableExtensions.ExpressionBuilder.GetMapExpression(Type sourceType, Type destinationType, Object parameters, MemberInfo[] membersToExpand)\r\n at AutoMapper.QueryableExtensions.ProjectionExpression.ToCore[TResult](Object parameters, IEnumerable1 memberPathsToExpand)\r\n at AutoMapper.QueryableExtensions.ProjectionExpression.To[TResult](Object parameters, Expression1[] membersToExpand)\r\n at AutoMapper.QueryableExtensions.Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Object parameters, Expression1[] membersToExpand)\r\n at AutoMapper.Mapper.ProjectTo[TDestination](IQueryable source, Object parameters, Expression1[] membersToExpand)\r\n at MyProject.Core.Base.MyProjectQueryBase2.ProjectTo[TDestination](IQueryable source) in C:\Users\shodg\MyProject\src\MyProject.GraphQL\Core\Base\MyProjectQueryBase.cs:line 65\r\n at MyProject.Core.Base.MyProjectQueryBase2.ProjectToListAsync[TDestination](IQueryable source) in C:\\Users\\shodg\\MyProject\\src\\MyProject.GraphQL\\Core\\Base\\MyProjectQueryBase.cs:line 71\r\n at MyProject.Queries.TimeEntryQuery.Resolve(ResolveFieldContext1 context) in C:\Users\shodg\MyProject\src\MyProject.GraphQL\Queries\TimeEntryQuery.cs:line 60\r\n at MyProject.Core.Base.MyProjectQueryBase2.InternalResolve(ResolveFieldContext1 context) in C:\Users\shodg\MyProject\src\MyProject.GraphQL\Core\Base\MyProjectQueryBase.cs:line 47\r\n at Abp.Threading.InternalAsyncHelper.AwaitTaskWithPostActionAndFinallyAndGetResult[T](Task1 actualReturnValue, Func1 postAction, Action`1 finalAction)\r\n at GraphQL.Instrumentation.MiddlewareResolver.Resolve(ResolveFieldContext context)\r\n at GraphQL.Execution.ExecutionStrategy.ExecuteNodeAsync(ExecutionContext context, ExecutionNode node)\r\n --- End of inner exception stack trace ---"


5 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @tusksoft

    Did you add mapping from TimeEntry to TimeEntryDto in ustomDtoMapper.cs ?

  • User Avatar
    0
    tusksoft created

    We did not add the mapping in CustomDtoMapper, as we are bypassing the use of automapper altogether. We use the follow code to map entities to Dto:

        public abstract class ViewEntityModel<TEntity, TViewModel, TPrimaryKey> : EntityDto<TPrimaryKey>, IViewModel<TEntity> where TEntity : class
            where TViewModel : class, IViewModel<TEntity>, new()
        {
    
            public static TViewModel CreateFrom(TEntity entity)
            {
                var vm = new TViewModel();
                vm.MapFrom(entity);
    
                return vm;
            }
    
            public abstract void MapFrom(TEntity entity);
        }
    

    Is it possible to take advantage of GraphQL while doing custom mapping, or are we forced to use Automapper? Thanks.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @tusksoft,

    Yes, AutoMapper mapping is required by default. Could you first try defining mapping and see if it works ?

    Thanks,

  • User Avatar
    0
    tusksoft created

    It does work when I add mappings in the CustomDtoMapper.cs in GraphQL. I was just curious if we could enable GraphQL without using AutoMapper at all. It sounds like that it not an option, unfortunately. Let me know if I'm mistaken.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    For example, User is mapped here https://github.com/aspnetzero/aspnet-zero-core/blob/dev/aspnet-core/src/MyCompanyName.AbpZeroTemplate.GraphQL/Queries/UserQuery.cs#L83. You can change this line to use any other approach insted of AutoMapper. It will be same for your own Query implementation.