简体   繁体   中英

Using projections without returning IQueryable, GraphQL HotChocolate

Is there a way to use projections if I don't want my services to return IQueryable?

I am thinking of something like, my resolver could map input to an Expression and then call the service class, then query is built and executed based on the provided expression, converted to some read only collection and returned to the user.

Something like the following:

 public async Task<IReadOnlyList<TestPayload>> GetAllTests(
                                             [Service] ITestService, 
                                             CancellationToken cancellationToken, 
                                             object[] requestedFields) => 
            await service.GetAllAsync(requestedFields, cancellationToken);

Then in my service:

var expression = BuildExpression(requestedFields);

var output = testRepository.Queryable()
                                 .Select(expression)
                                    .AsNoTracking();
return output.ToListAsync();

Can you point me in some direction regarding this?


EDIT:

As per @Pascal's answer I added HotChocolate.Data package and invoked Project(context) extension method on my IQueryable.

Right now I have an issue with my payload(model) classes, but I'm not quite sure why.

The following example will return all columns and will not apply projection.

       [UseProjection]
       public async Task<IReadOnlyList<TestPayload>> TestGetAll([Service] ITestService testService, IResolverContext context, CancellationToken cancellationToken) 
        {
            return await testService.GetAllAsync(context, cancellationToken);
        }

This one will work, and will project to the query and return only what's requested. Notice that the only thing that's different is the return type (IReadOnly instead of IReadOnly).

       [UseProjection]
       public async Task<IReadOnlyList<Test>> TestGetAll([Service] ITestService testService, IResolverContext context, CancellationToken cancellationToken) 
        {
            return await testService.GetAllAsync(context, cancellationToken);
        }

Inside the service:

var tests = testRepository.Queryable()
                         .Project<Test>(context)
                        .AsNoTracking();

I guess it is because of the resolver that is now working with the dto TestPayload type and then inside the service trying to project to the IQueryable of entity(Test), but I'm not sure how to overcome it.

Yes there is, HotChocolate.Data provides extension methods on top of IQueryable

 public async Task<IReadOnlyList<TestPayload>> GetAllTests(
    [Service] ITestService, 
    CancellationToken cancellationToken, 
    IResolverContext context) => 
    await service.GetAllAsync(context, cancellationToken);
var output = testRepository.Queryable()
     .Project(context)
     .AsNoTracking();
return output.ToListAsync();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM