Репозитории данных
Репозитории данных Spring Data предоставляют полезную абстракцию для работы с сущностями, особенно для реализации бизнес-логики.
Репозитории данных Jmix построены на базе Spring Data, но внутри используют DataManager. Это позволяет использовать удобный интерфейс репозиториев и при этом иметь полную поддержку продвинутых возможностей доступа к данным Jmix, таких как события сущностей, ссылки между сущностями из разных хранилищ, проверки доступа к данным и т.п.
В текущей версии 2.3 API репозиториев данных Jmix помечен как экспериментальный. В следующем функциональном релизе в него могут быть внесены незначительные изменения и API станет стабильным. |
Работа с репозиториями данных
Вы можете создать репозиторий данных Jmix двумя способами: используя Мастер создания репозитория данных или следуя шагам, описанным ниже.
-
Создайте интерфейс, унаследованный от
JmixDataRepository
. Используйте класс сущности и класс идентификатора сущности в качестве параметров типаJmixDataRepository
. Например:public interface CustomerRepository extends JmixDataRepository<Customer, UUID> { }
-
Добавьте аннотацию
@EnableJmixDataRepositories
главному классу приложения или классу конфигурации дополнения:import io.jmix.core.repository.EnableJmixDataRepositories; // ... @SpringBootApplication @EnableJmixDataRepositories public class DemoApplication implements AppShellConfigurator {
Jmix проинициализирует все репозитории данных, расположенные внутри и ниже базового пакета приложения или дополнения. Если требуется более тонкая настройка поиска репозиториев, используйте атрибуты аннотации
basePackages
,excludeFilters
иincludeFilters
. -
Инжектируйте репозиторий в бины Spring или UI-контроллеры с помощью аннотации
@Autowired
:@Autowired private CustomerRepository customerRepository;
Особенности JmixDataRepository
Интерфейс JmixDataRepository
расширяет стандартный интейфейс PagingAndSortingRepository из Spring Data. Он предоставляет несколько собственных методов, учитывающих специфику Jmix:
-
Методы загрузки, такие как
findById()
илиfindAll()
, могут принимать фетч-план. -
Метод
create()
создает новый экземпляр сущности. -
Метод
getById()
с обязательным результатом загружает сущность по идентификатору и выбрасывает исключение, если сущность не найдена. -
Метод
getDataManager()
возвращаетDataManager
для использования в методах по умолчанию. -
Метод
save()
сохраняет предоставленную сущность и возвращает сохраненный экземпляр, загруженный с указанным планом выборки. Метод принимает сущность для сохранения и план выборки, который будет применен при перезагрузке сохраненной сущности. Сущность не может бытьnull
, а план выборки должен быть применим к сущности.
Методы загрузки репозиториев, унаследованных от JmixDataRepository
, теперь поддерживают дополнительный аргумент типа JmixDataRepositoryContext
. Это позволяет передавать параметры фильтрации, пейджинга и сортировки, собранные в объект LoadContext
из UI-компонентов. В результате все функции компонентов genericFilter
, simplePagination
и dataGrid
будут полноценно работать с репозиториями данных.
Вы можете применить аннотацию io.jmix.core.repository.ApplyConstraints
к своему репозиторию данных. Если значение аннотации равно false
, репозиторий использует UnconstrainedDataManager
вместо DataManager
. Значение аннотации по умолчанию - true
.
Аннотация @ApplyConstraints
может быть использована не только для всего класса, но и для отдельных методов, чтобы игнорировать или, наоборот, включить ограничения только для них.
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();
}
В приведенном выше примере @ApplyConstraints(false)
применяется только к двум методам, и для них будет использоваться UnconstrainedDataManager
.
В приведенном ниже примере ограничения отключены для всего класса, но включены точечно для отдельных методов:
@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);
}
Методы findAll()
и searchByIdNotNull()
будут использовать обычный DataManager
, в то время как все остальные методы будут использовать UnconstrainedDataManager
.
Следующие аннотации можно использовать на кастомных методах запросов:
-
@io.jmix.core.repository.Query
задает строку JPQL аналогично аннотации@Query
в Spring Data JPA. -
@io.jmix.core.repository.FetchPlan
задает фетч-план для загрузки данных. -
@io.jmix.core.repository.QueryHints
и@jakarta.persistence.QueryHint
позволяют вам указать хинты для отключения мягкого удаления и использования кэша запросов.
Если имя метода/запроса и параметры метода имеют разные значения для плана выборки и хинтов, то окончательные значения выбираются на основе приоритета, от самого высокого к самому низкому. FetchPlan:
Hints:
Для хинтов с одинаковым ключом значение из источника с более высоким приоритетом переопределит значение из источника с более низким приоритетом. Разные ключи будут объединены. |
Примеры методов запросов
Репозитории данных Jmix поддерживают стандартную возможность Spring Data выводить запрос из имени метода, например:
List<Customer> findByEmailContainingIgnoreCase(String emailPart);
Аналогично Spring Data JPA, JPQL-запрос можно явно задать с помощью аннотации @io.jmix.core.repository.Query
:
@Query("select c from sample_Customer c where c.email like :email")
List<Customer> findCustomersByEmail(@Param("email") String emailPart);
Методы запросов могут принимать объект Pageable
для постраничной загрузки и сортировки:
Page<Customer> findByEmailContainingIgnoreCase(String emailPart, Pageable pageable);
Другой специально обрабатываемый параметр, который можно использовать в методах запросов - фетч-план:
List<Customer> findByEmailContainingIgnoreCase(String emailPart, FetchPlan fetchPlan);
Разделяемый фетч-план можно задавать по имени в аннотации @io.jmix.core.repository.FetchPlan
:
@FetchPlan("customer-minimal")
List<Customer> findByEmail(String email);
Кэшируемый запрос:
@QueryHints(@QueryHint(name = PersistenceHints.CACHEABLE, value = "true"))
List<Customer> findByEmail(String email);