spatialNinja
spatialNinja

Reputation: 3

Java DataLoader: Graphql query mismatches results

I am using boot-graphql-kick-start in my project. When I used Dataloader, the result is missmatching. where am I wrong? Can you help me?

Query:

query USE_ROLES_BY_PROJECT_ID($projectId: Int) {  # parameter value  =3 
  userRolesByProjectId(projectId:$projectId) {
    id
    roleId
    projectId
    role {
      id
      name
      shortCode
    }
  }

Result:

{
  "data": {
    "userRolesByProjectId": [
      {
        "id": 2,
        "projectId": 3,
        "roleId": 5,
        "role": {
          "id": 8,
          "name": "TESTER",
          "shortCode": "TESTER"
        }
      },
      {
        "id": 81,
        "projectId": 3,
        "roleId": 8,
        "role": {
          "id": 5,
          "name": "PROJECTADMIN",
          "shortCode": "PROJECTADMIN"
        }
      }
    ]
  }
}

ResultForDetail

Entity: I have ManyToOne Relation With My RoleEntity

@Entity
public class UserRole extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_cfcs_user_role")
    @Column(name = "id")
    private Long id;

    @Column(name = "role_id")
    private Long roleId;

    @Column(name = "project_id")
    private Long projectId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "role_id", referencedColumnName = "id", insertable = false, updatable = false)
    private Role role;
}

QueryResolver:

@Component
public class UserRolesQueryResolver implements GraphQLQueryResolver {
    private final UserRoleService userRolesService;
    
    public List<UserRole> userRolesByProjectId(Long projectId){
        return userRolesService.getUserRole(projectId);
    }
}

@Component
public class UserRoleResolver 
implements GraphQLResolver<UserRole> {
    private final IRoleService roleService;
 
    public CompletableFuture<Role> role(UserRole userRole, DataFetchingEnvironment dfe) {
        final DataLoader<Long, Role> dataloader = dfe.getDataLoaderRegistry()
                .getDataLoader("userRoleRoleDataLoader");
        return dataloader.load(userRole.getRoleId());
    }
}

DataLoader Method: I'm Using BatchLoader for n+1.

 private void role(DataFetchingEnvironment dfe) {
        BatchLoader<Long, Role> userRoleRoleDataLoader =
                roles -> CompletableFuture.supplyAsync(() -> {
                    return roleService.findByIdIn(roles);
                });
        dfe.getDataLoaderRegistry().register("userRoleRoleDataLoader",
                DataLoader.newDataLoader(userRoleRoleDataLoader));
    }

Hibernate Query: In dataLoader Iam wathcing the result. Is seems correctly

select role0_.id         as id1_18_,
       role0_.name       as name9_18_,
       role0_.short_code as short_c10_18_
from app_role role0_
where (role0_.is_actv = 1)
  and (role0_.id in (?, ?))

Upvotes: 0

Views: 558

Answers (1)

puelo
puelo

Reputation: 6047

I had the same problem and the solution is to sort the output from your data loader according to the input. The order of the output has to match the order of the input. For you this probably means something like this:

private void role(DataFetchingEnvironment dfe) {
        BatchLoader<Long, Role> userRoleRoleDataLoader =
                roleIds -> CompletableFuture.supplyAsync(() -> {
                    List<Role> roles = roleService.findByIdIn(roleIds);
                    roles.sort(Comparator.comparing(n -> roleIds.indexOf(n.getId())));
                    return roles;
                });
        dfe.getDataLoaderRegistry().register("userRoleRoleDataLoader",
                DataLoader.newDataLoader(userRoleRoleDataLoader));
    }

Upvotes: 1

Related Questions