SPQR Dataloder doesn't allow null values - Exception while fetching data : null
See original GitHub issue@kaqqao @BaldyLocks @vkachan @csueiras @kicktipp Hi all,
I have set up some batch DataLoaders for each entity (that have relationships with others) in order to solve the N+1 Problem with GraphQL/SPQR - and it works. HOWEVER, when I have a @OneToOne
or @ManyToMany
relation on some entity that is null, an Exception while fetching data (/getAllEmployees[6]/company) : null
.
Here is the resolver for the company field of each employee:
@GraphQLQuery(name = "company")
public CompletableFuture<Company> getCompany(
@GraphQLContext @Valid @GraphQLNonNull Employee employee, @GraphQLEnvironment ResolutionEnvironment env) {
DataLoader<UUID, Company> loader = env.dataFetchingEnvironment.getDataLoader("company");
return loader.load(employee.getCompany().getId());
}
And the DataFetcher,
@Component
public class DataLoaderFactory implements DataLoaderRegistryFactory {
private static CompanyDao companyDao;
private static final BatchLoader<UUID, Company> companyLoader = DataLoaderFactory::companies;
/* ...... */
@Autowired
public DataLoaderFactory(CompanyDao companyDao, /* ...... */) {
DataLoaderFactory.companyDao = companyDao;
/* ...... */
}
public static CompletableFuture<List<Company>> companies(List<UUID> ids) {
return CompletableFuture.completedFuture(companyDao.findAllById(ids));
}
/* ...... */
@Override
@Bean
public DataLoaderRegistry createDataLoaderRegistry() {
DataLoaderRegistry allLoaders = new DataLoaderRegistry();
allLoaders.register("company", new DataLoader<>(companyLoader));
/* ...... */
return allLoaders;
}
}
And for some context, here are the entities:
For the Employee
@Setter
@Getter
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class Employee implements Serializable {
private static final long serialVersionUID = 684733882540759135L;
@Id
@GeneratedValue
@Column(columnDefinition = "uuid", updatable = false)
@GraphQLQuery(name = "id", description = "A Person's Id")
private UUID id;
@NotNull(message = "There must be a Person's Name!")
@GraphQLQuery(name = "fullName", description = "A Person's Name")
private String fullName;
@NotNull(message = "A Person must have an Age!")
@GraphQLQuery(name = "age", description = "A Person's Age")
private int age;
@NotNull(message = "A Person must have a Vehicle!")
@GraphQLQuery(name = "personalVehicle", description = "A Person's Mode of Transport")
private Vehicle personalVehicle;
@ManyToOne(targetEntity = Company.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@GraphQLQuery(name = "company", description = "The Company a Person works for")
private Company company;
@GraphQLQuery(name = "roles", description = "The Role a Person plays in their Company")
@OneToMany(
targetEntity = Role.class,
orphanRemoval = true,
fetch = FetchType.LAZY,
mappedBy = "employee",
cascade = CascadeType.ALL)
private List<Role> roles = new ArrayList<>();
public enum Vehicle {
CAR,
BUS,
VAN,
BICYCLE,
MOTORBIKE,
SCOOTER
}
}
For the Company
@Setter
@Getter
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class Company implements Serializable {
private static final long serialVersionUID = -6007975840330441233L;
@Id
@GeneratedValue
@Column(columnDefinition = "uuid", updatable = false)
@GraphQLQuery(name = "id", description = "A Company's Id")
private UUID id;
@NotNull(message = "There must be a Company Name!")
@GraphQLQuery(name = "name", description = "A Company's Name")
private String name;
@Min(10000)
@NotNull(message = "You gotta tell us how rich you are!")
@GraphQLQuery(name = "balance", description = "A Company's Dollar")
private BigDecimal balance;
@NotNull(message = "There must be a Company Type!")
@GraphQLQuery(name = "type", description = "The type of company")
private CompanyType type;
@GraphQLQuery(name = "offices", description = "The Company's offices")
@OneToMany(
targetEntity = Office.class,
orphanRemoval = true,
fetch = FetchType.LAZY,
mappedBy = "company",
cascade = CascadeType.ALL)
private List<Office> offices;
public enum CompanyType {
PRIVATE_LIMITED,
SOLE_TRADER,
PUBLIC
}
}
Any help, comments or clarification would be much, much appreciated - I’m probably missing out something stupid!!
Issue Analytics
- State:
- Created 2 years ago
- Comments:9 (2 by maintainers)
Top Results From Across the Web
leangen/graphql-spqr - Gitter
I noticed that graphql-java makes DataFetcher s wrap checked exceptions into runtime exceptions even though the surrounding code can handle both just fine....
Read more >GraphQL Dataloader fails if backend returns null values
Found that the backend server is not even sending 'null', it just ignores the missing record.
Read more >Error 'Empty Column is found' in Data Loader - Salesforce Help
To resolve this error you will need to ensure that any empty columns are removed from your .csv file. Note: This error does...
Read more >Using Micronaut and GraphQL with transactions and security ...
DataLoader - Loading initial data to the database [main] DEBUG ... At the moment I'm writing this article graphql-spqr is very poorly ...
Read more >30 Days With GraphQL - Better Programming
Under-fetching is when you wanted a little bit more but the API ... For example, this is a valid value [1,2,null] , but...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Pheeew, this is a rather involved scenario that I really can’t answer it without investigation. There’s nothing in SPQR that deals with DataLoader in any meaningful way. That is to say, you should be in the exact same situation if you were using DataLoader without SPQR. So whatever is happening likely isn’t really SPQR specific. That said, the Java impl of DataLoader has been a bit of mine field… so it may well be a bug in there. I think I even vaguely remember it freaking out on nulls. Try searching their issues. Can you maybe try using their latest release? I believe there was a big release recently. If I’m wrong, please try building their master locally and using that. If it breaks compatibility, let me know and I’ll have a look what changes are needed in the starter.
I was hoping it would be compatible enough not to cause issues when you override the version. But after looking into the comments, issues and PRs on the DataLoader project, I’m not exactly hopeful any longer. I personally find DataLoader to be too messy for its worth and tend to stay away from it, so I recommend you consider simpler approaches to batching e.g. looking ahead and prefetching using the LocalContext.