Data Repositories
Spring Data repositories provide a useful abstraction for working with entities, especially when implementing business logic.
Jmix data repositories are built on top of Spring Data and use DataManager under the hood. It allows you to utilize the convenient repository interface while having the full support for advanced Jmix data access features, such as entity events, cross-datastore references, data access checks, etc.
Working with Data Repositories
You can create a Jmix data repository in two ways: using the Data Repository Wizard or following the steps below.
-
Create an interface extending
JmixDataRepository
. Use the entity class and the entity identifier class as type parameters forJmixDataRepository
. For example:public interface CustomerRepository extends JmixDataRepository<Customer, UUID> { }
-
Add
@EnableJmixDataRepositories
annotation to the main application class or the add-on configuration:import io.jmix.core.repository.EnableJmixDataRepositories; // ... @SpringBootApplication @EnableJmixDataRepositories public class DemoApplication implements AppShellConfigurator {
Jmix will initialize all data repositories located under the base package of the application or the add-on. If you need more customized control over where to search for repositories, use the
basePackages
,excludeFilters
andincludeFilters
attributes of the annotation. -
Inject your repository into Spring beans or UI controllers using the
@Autowired
annotation:@Autowired private CustomerRepository customerRepository;
JmixDataRepository Features
The JmixDataRepository
interface extends the standard Spring Data PagingAndSortingRepository. It provides a few own methods considering Jmix specifics:
-
Load methods, such as
findById()
orfindAll()
, can accept a fetch plan. -
create()
method instantiates a new entity. -
getById()
method with the non-optional result loads an entity by id and throws the exception if the entity is not found. -
getDataManager()
method returns DataManager to use in default methods. -
save()
method persists the provided entity and returns saved instance, loaded with the specified fetch plan. The method accepts the entity to be saved and fetch plan to apply when reloading the saved entity. The entity cannot be null, and fetch plan must be applicable to the entity.
Load methods of repositories inherited from JmixDataRepository
support an additional argument of the JmixDataRepositoryContext
type. It allows you to pass the filtering, paging and sorting parameters collected from UI components to the LoadContext
object. As a result, all the features of genericFilter
, simplePagination
and dataGrid
components will work seamlessly with data repositories.
You can apply the io.jmix.core.repository.ApplyConstraints
annotation to your data repository. If the value of the annotation is false
, the repository uses UnconstrainedDataManager
instead of DataManager
. The default annotation value is true
.
The @ApplyConstraints
annotation can be used not only for the entire class, but also for individual methods to either ignore or enable constraints for them only.
public interface OrderRepository extends JmixDataRepository<Order, UUID> {
@Override
Iterable<Order> findAll(Sort sort, @Nullable FetchPlan fetchPlan);
@Override
@ApplyConstraints(false)
Iterable<Order> findAll(FetchPlan fetchPlan);
@ApplyConstraints(false)
List<Order> findByIdNotNull();
}
In the example above, @ApplyConstraints(false)
is applied specifically to two methods, and they will use UnconstrainedDataManager
.
In the example below, constraints are disabled for the entire class, but are specifically enabled for individual methods:
@ApplyConstraints(false)
public interface ProductRepository extends JmixDataRepository<Product, UUID> {
@Override
Iterable<Product> findAll(Sort sort, @Nullable FetchPlan fetchPlan);
@Override
@ApplyConstraints
Page<Product> findAll(Pageable pageable);
List<Product> getByIdNotNull();
@ApplyConstraints
List<Product> searchByIdNotNull();
List<Product> searchById(UUID id);
}
The findAll()
and searchByIdNotNull()
methods will use the regular DataManager
, while all other methods will use UnconstrainedDataManager
.
You can use the following annotations on custom query methods:
-
@io.jmix.core.repository.Query
defines a JPQL query string, similar to the Spring Data JPA@Query
annotation. -
@io.jmix.core.repository.FetchPlan
defines a fetch plan to be used when loading data. -
@io.jmix.core.repository.QueryHints
and@jakarta.persistence.QueryHint
allow you to specify hints for turning soft deletion off and using query cache.
If a method name/query and method parameters specify different values for fetch plan and hints, the final values are based on priority, from highest to lowest. FetchPlan:
Hints:
For hints with the same key, the value from the higher priority source will override the value from the lower priority source. Different keys will be merged. |
Query Method Examples
Jmix data repositories support the standard Spring Data feature of deriving the query from the method name, for example:
List<Customer> findByEmailContainingIgnoreCase(String emailPart);
Similar to Spring Data JPA, a JPQL query can be defined explicitly using the @io.jmix.core.repository.Query
annotation:
@Query("select c from sample_Customer c where c.email like :email")
List<Customer> findCustomersByEmail(@Param("email") String emailPart);
Query methods can accept Pageable
for pagination and sorting:
Page<Customer> findByEmailContainingIgnoreCase(String emailPart, Pageable pageable);
Another special parameter that can be passed to query methods is a fetch plan:
List<Customer> findByEmailContainingIgnoreCase(String emailPart, FetchPlan fetchPlan);
A shared fetch plan can be defined in the @io.jmix.core.repository.FetchPlan
annotation on the query method:
@FetchPlan("customer-minimal")
List<Customer> findByEmail(String email);
A cacheable query:
@QueryHints(@QueryHint(name = PersistenceHints.CACHEABLE, value = "true"))
List<Customer> findByEmail(String email);