使用 Data Repositories
Spring Data repositories 为实体操作提供了非常有用的抽象,特别是实现业务逻辑的时候。
Jmix data repositories 基于 Spring Data 构建,但是在底层使用的是 DataManager。这样既可以使用方便的 repository 接口,又能支持 Jmix 中的高级数据访问功能,比如 实体事件,跨数据存储实体引用,数据访问权限检查 等。
使用 Data Repositories
Jmix data repository 有两种创建方式:使用 Data Repository 向导,或按照下面的步骤手动创建。
-
创建一个接口,继承自
JmixDataRepository
。使用实体类和实体 ID 类作为JmixDataRepository
的参数。示例:public interface CustomerRepository extends JmixDataRepository<Customer, UUID> { }
-
在 Jmix 主程序类或者扩展组件的配置类上添加
@EnableJmixDataRepositories
注解:import io.jmix.core.repository.EnableJmixDataRepositories; // ... @SpringBootApplication // TODO uncomment when https://github.com/jmix-framework/jmix/issues/3772 is fixed // @EnableJmixDataRepositories public class DemoApplication implements AppShellConfigurator {
Jmix 会初始化应用程序和扩展组件基础包内的所有 data repositories。如果需要对搜索和初始化 repositories 做进一步自定义,可以使用注解的
basePackages
、excludeFilters
和includeFilters
属性配置。 -
在 Spring bean 或 UI 控制器内使用
@Autowired
注解注入 repository:@Autowired private CustomerRepository customerRepository;
JmixDataRepository 的功能
JmixDataRepository
接口派生自标准的 Spring Data PagingAndSortingRepository。此外,提供了一些 Jmix 特有的方法:
-
数据加载方法支持 fetch plan,比如
findById()
或findAll()
。 -
create()
方法 初始化 一个新实体。 -
返回非 Optional 对象的
getById()
方法会在找不到实体时抛出异常。 -
getDataManager()
返回默认方法中使用的 DataManager。 -
save()
方法可以对实体进行持久化,并返回保存后的实例,实例的加载使用的是指定的 fetch plan。方法接收需要保存的实体和加载实体使用的 fetch plan 作为参数。实体不能为null
,fetch plan 必须与实体匹配。
从 JmixDataRepository
继承的数据加载方法支持一个 JmixDataRepositoryContext
类型的附加参数。可以通过这个参数将从 UI 组件搜集的过滤、分页、排序等参数传递给 LoadContext
对象。从而使用 data repository 也可以无缝支持 genericFilter
、simplePagination
和 dataGrid
组件的全部功能。
Data Repositories 可以使用 io.jmix.core.repository.ApplyConstraints
注解。如果注解的值是 false
,则 Repository 使用 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
。
可以使用下列注解自定义查询方法:
如果方法名/查询与方法参数使用了不同的 fetch plan 或 hint,那么最后的值会按照优先级从高往低使用。 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. |
方法示例
Jmix data repositories 支持从方法名生成查询语句的 Spring Data 标准功能,示例:
List<Customer> findByEmailContainingIgnoreCase(String emailPart);
与 Spring Data JPA 类似,可以使用 @io.jmix.core.repository.Query
注解显式定义 JPQL 语句:
@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);
查询方法还支持一个特殊的 fetch plan 参数:
List<Customer> findByEmailContainingIgnoreCase(String emailPart, FetchPlan fetchPlan);
共享的 fetch plan 可以在查询方法的 @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);