Data Stores
A data store represents a database or any other source of data in your application.
Jmix provides JpaDataStore which stores JPA entities in a relational database. This is the main persistence mechanism in Jmix applications, and when we mention a data store in this manual, we always mean JpaDataStore if not explicitly stated otherwise.
Main Store
When you create a new Jmix project in Studio, it has a single data store called main that connects to a relational database. The connection parameters are specified in the following application properties:
main.datasource.url = jdbc:hsqldb:file:.jmix/hsqldb/sample
main.datasource.username = sa
main.datasource.password =
| Use Studio interface to define database connection properties for a data store. |
The main application class contains a corresponding JDBC DataSource bean declaration:
@Bean
@Primary
@ConfigurationProperties("main.datasource")
DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("main.datasource.hikari")
DataSource dataSource(DataSourceProperties dataSourceProperties) {
return dataSourceProperties.initializeDataSourceBuilder().build();
}
All JPA entities by default are associated with the main data store.
Additional Stores
In order to work with multiple databases, you need additional data stores.
| Use Studio interface to define additional data stores. |
Each additional store has a unique name, which is specified in the comma-separated list of the jmix.core.additionalStores application property. Parameters of the database connection have the store name as a prefix. In the examples below, the locations additional store is configured:
jmix.core.additionalStores = locations,inmem
locations.datasource.url = jdbc:hsqldb:file:.jmix/hsqldb/locations
locations.datasource.username = sa
locations.datasource.password =
For each additional store, Studio creates a Spring configuration class and defines the JDBC DataSource and other related beans in it:
@Configuration
public class LocationsStoreConfiguration {
@Bean
@ConfigurationProperties("locations.datasource")
DataSourceProperties locationsDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties(prefix = "locations.datasource.hikari")
DataSource locationsDataSource(@Qualifier("locationsDataSourceProperties") DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
@Bean
LocalContainerEntityManagerFactoryBean locationsEntityManagerFactory(
@Qualifier("locationsDataSource") DataSource dataSource,
JpaVendorAdapter jpaVendorAdapter,
DbmsSpecifics dbmsSpecifics,
JmixModules jmixModules,
Resources resources) {
return new JmixEntityManagerFactoryBean("locations", dataSource, jpaVendorAdapter, dbmsSpecifics, jmixModules, resources);
}
@Bean
JpaTransactionManager locationsTransactionManager(@Qualifier("locationsEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JmixTransactionManager("locations", entityManagerFactory);
}
@Bean
public SpringLiquibase locationsLiquibase(LiquibaseChangeLogProcessor processor, @Qualifier("locationsDataSource") DataSource dataSource) {
return JmixLiquibaseCreator.create(dataSource, new LiquibaseProperties(), processor, "locations");
}
}
To associate an entity with an additional data store, use the @Store annotation on the entity class:
@Store(name = "locations")
@JmixEntity
@Table(name = "SAMPLE_COUNTRY")
@Entity(name = "sample_Country")
public class Country {
Studio adds @Store annotation when you select an additional data store for the entity in the entity designer.
|
In the example above, the Country entity will be stored in the database connected as the locations data store.
Custom Data Store
A custom data store may help you to work with some DTO entities in the same way as with JPA entities - by using DataManager. If your DTO entity is associated with a custom store, DataManager will delegate its CRUD operations to your data store and use it when resoving references to your DTOs from other entities.
Let’s consider the process of creating a custom data store. Imagine a transient Metric entity and an in-memory store for it.
-
Create a class that implements the
DataStoreinterface. The class must be a Spring prototype bean. The example below contains a primitive implementation that is capable of storing entities of different types in memory.@Component("sample_InMemoryStore") @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class InMemoryStore implements DataStore { // ... } -
Create a class that implements the
StoreDescriptorinterface. It must be a Spring singleton bean, and itsgetBeanName()method must return the name of the data store implementation bean created on the previous step:@Component("sample_InMemoryStoreDescriptor") public class InMemoryStoreDescriptor implements StoreDescriptor { @Override public String getBeanName() { return "sample_InMemoryStore"; } @Override public boolean isJpa() { return false; } } -
Add the data store name (
inmemin this case) to thejmix.core.additionalStoresproperty:jmix.core.additionalStores = locations,inmem -
Set the
StoreDescriptorbean name in thejmix.core.storeDescriptor_<store_name>property:jmix.core.storeDescriptor_inmem = sample_InMemoryStoreDescriptor -
Add
@Storeannotation to the entity:@Store(name = "inmem") (1) @JmixEntity(name = "sample_Metric", annotatedPropertiesOnly = true) (2) public class Metric { -
Now you can save and load the entity using
DataManagerand it will delegate the CRUD operations to your custom data store:Metric metric = dataManager.create(Metric.class); metric.setName("test"); metric.setValue(10.0); dataManager.save(metric); Metric metric1 = dataManager.load(Id.of(metric)).one();Also, if another entity has a reference to
Metric, theMetricinstance will be loaded automatically when accessing the reference attribute.