Best Practices
Security
-
Always use validation in production:
LoadOptionsValidator validator = LoadOptionsValidator.builder() .maxTake(1_000) .maxSkip(10_000) .build(); GridDataProvider gridDataProvider = new GridDataProvider(dataSource, validator); -
Set appropriate query timeouts:
gridDataProvider.setQueryTimeout(30); // 30 seconds for OLTP -
Never disable validation for public APIs
-
Use DataSource mode for connection pooling
-
Validate developer-defined SQL expressions in CI/CD
Performance
-
Create indexes on filtered/sorted columns:
CREATE INDEX idx_employees_lastname ON employees(last_name); CREATE INDEX idx_employees_salary ON employees(salary DESC); CREATE INDEX idx_employees_dept_salary ON employees(department_id, salary DESC); -
Use pagination for large result sets:
{"take": 100, "skip": 0, "requireTotalCount": true} -
Limit nested entity depth to avoid N+1 queries
-
Cache GridDataProvider instances (thread-safe in DataSource mode):
@Bean public GridDataProvider gridDataProvider(DataSource dataSource) { return new GridDataProvider(dataSource); }
Thread Safety
DataSource Mode (Recommended)
- Thread-safe for read operations (executeQuery, getData)
- NOT thread-safe for setters (
setQueryTimeout) - configure before sharing
Connection Mode
- NOT thread-safe
- Each thread should have its own GridDataProvider with its own Connection
Error Handling
try {
DevExtremeResult<Employee> result = gridDataProvider
.query(Employee.class)
.loadOptions(loadOptions)
.executeDevExtreme();
return result;
} catch (IllegalArgumentException e) {
// Invalid LoadOptions (validation failed)
log.error("Invalid request: {}", e.getMessage());
return ResponseEntity.badRequest().body(e.getMessage());
} catch (ConnectionValidationException e) {
// Database connection error
log.error("Database connection failed", e);
return ResponseEntity.status(503).body("Database unavailable");
} catch (QueryExecutionException e) {
// Query execution error
log.error("Query execution failed", e);
return ResponseEntity.status(500).body("Query failed");
} catch (FilterConversionException e) {
// Filter parsing error
log.error("Invalid filter: {}", e.getMessage());
return ResponseEntity.badRequest().body("Invalid filter");
}Last updated on