Представим, что вашему проекту срочно понадобился ORM, и вы хотите внедрить его как можно быстрее. В этой статье я хочу рассказать, как это можно сделать всего за четыре шага на примере использования open source проекта Apache Cayenne.
Для начала вкратце опишу механизм работы с данной библиотекой. Схема базы данных и модели описывается в xml файле, который может быть сгенерирован через GUI приложение или через консоль. Затем на основе xml файла генерируются java объекты, которые являются соответствующим отображением таблиц в базе. Последним шагом создается ServerRuntime
— объект, который инкапсулирует в себе весь стек Apache Cayenne.
Итак, перейдем к примеру. Что необходимо сделать:
- Создать схему базы данных
- Импортировать схему в проект, то есть получить xml файлы с описанием схемы
- Создать объектную модель, то есть сгенерировать java классы
- Проинициализировать
ServerRuntime
для доступа к базе данных из приложения
Что потребуется для начала? Уже существующий maven или gradle проект, Java 1.8+ и база данных. Мой тестовый проект использует maven, java 14 и самую свежую версию Apache Cayenne 4.2.M1. В качестве базы я использую mysql. Вы для своих проектов можете использовать стабильную версию 4.1 и любую из известных реляционных баз на ваш выбор.
Для наглядности я прикреплю ссылку на пример.
Создание схемы
Для примера создадим простейшую схему, состоящую из трех сущностей: марка авто, модель авто, отзыв на модель авто.
CREATE SCHEMA IF NOT EXISTS cars_demo; USE cars_demo;
CREATE TABLE car_brand (ID INT NOT NULL AUTO_INCREMENT, NAME VARCHAR(200) NULL, COUNTRY VARCHAR(200) NULL, PRIMARY KEY (ID)) ENGINE=InnoDB;
CREATE TABLE car_model (ID INT NOT NULL AUTO_INCREMENT, NAME VARCHAR(200) NULL, CAR_BRAND_ID INT NULL, PRIMARY KEY (ID)) ENGINE=InnoDB;
CREATE TABLE feedback (CAR_MODEL_ID INT NULL, ID INT NOT NULL AUTO_INCREMENT, FEEDBACK VARCHAR(200) NULL, PRIMARY KEY (ID)) ENGINE=InnoDB;
ALTER TABLE car_model ADD FOREIGN KEY (CAR_BRAND_ID) REFERENCES car_brand (ID) ON DELETE CASCADE;
ALTER TABLE feedback ADD FOREIGN KEY (CAR_MODEL_ID) REFERENCES car_model (ID) ON DELETE CASCADE;
Первый шаг пройден, двигаемся ко второму.
Импорт схемы
Здесь уже начинается непосредственное использование библиотеки. Для начала подключим необходимый плагин к проекту:
<plugin>
<groupId>org.apache.cayenne.plugins</groupId>
<artifactId>cayenne-maven-plugin</artifactId>
<version>${cayenne.version}</version>
<configuration>
<dataSource> <!--1-->
<driver>com.mysql.jdbc.Driver</driver>
<url>jdbc:mysql://127.0.0.1:3306/cars_demo</url>
<username>root</username>
<password>root</password>
</dataSource>
<cayenneProject>${project.basedir}/src/main/resources/cayenne/cayenne-project.xml</cayenneProject> <!--2-->
<map>${project.basedir}/src/main/resources/cayenne/datamap.map.xml</map> <!--3-->
<dbImport> <!--4-->
<defaultPackage>cayenne.note.project.model</defaultPackage>
<catalog>cars_demo</catalog>
</dbImport>
</configuration>
<dependencies>
<dependency> <!--5-->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</plugin>
- (1) DataSource, для подключения к базе
- (2) Путь, где будет лежать сгенерированный xml, который необходим для запуска Cayenne
- (3) Путь, где будет лежать xml с описанием модели и базы
- (4) Базовый пакет, где позже будут находиться сгенерированные классы
- (5) Зависимость от mysql-connector для работы с mysql
Далее в консоли запускаем импорт модели:
mvn cayenne:cdbimport
После выполнения этой команды должны появится два файла, указанные в (2) и (3). Как я уже говорил, файл cayenne-project.xml является служебным файлом, необходимым для работы библиотеки. Файл datamap.map.xml — это описание модели базы данных и ее объектного отображения, а также всех связей.
Пару слов о процессе cdbimport
: по умолчанию он импортирует всю схему, включая все связи. Данная команда может быть кастомизирована. Вы можете указать, какие сущности стоит включить в импорт, какие исключить, есть возможность указать паттерн для импорта таблиц. Более подробно с этим можно ознакомиться в документации.
Генерация классов
В предыдущем пункте мы сгенерировали описание модели, теперь же нам необходимо сгенерировать java классы, которые можно будет использовать в проекте. Сделать это очень просто, достаточно просто запустить в консоли команду:
mvn cayenne:cgen
После успешной генерации в пакете, который был указан в настройке плагина, будет находиться набор сгенерированных сущностей. Стоит обратить внимание, что сгенерировалось два набора классов. Первый находится в пакете auto
и является служебным. Не стоит модифицировать эти классы, так как все изменения исчезнут при следующей генерации. Для пользовательских изменений существуют классы без нижнего подчеркивания, которые наследуются от классов из пакета auto
. Именно они предназначаются для прямого использования и кастомизации.
Пример использования
Мы на финишной прямой, осталось только привести пример использования Apache Cayenne.
Создадим ServerRuntime
— это основной стэк Cayenne, который создается один раз для всего проекта.
Из рантайма всегда можно получить ObjectContext
— объект, который используется для работы с базой данных.
ServerRuntime cayenneRuntime = ServerRuntime.builder()
.dataSource(DataSourceBuilder
.url("jdbc:mysql://127.0.0.1:3306/cars_demo")
.driver("com.mysql.cj.jdbc.Driver")
.userName("root") // Need to change to your username
.password("root") // Need to change to your password
.build())
.addConfig("cayenne/cayenne-project.xml")
.build();
ObjectContext context = cayenneRuntime.newContext();
Создадим несколько сущностей и отправим их в базу:
CarBrand carBrand = context.newObject(CarBrand.class);
carBrand.setName("BMW");
carBrand.setCountry("Germany");
CarModel carModel = context.newObject(CarModel.class);
carModel.setName("i3");
carModel.setCarBrand(carBrand);
Feedback feedback = context.newObject(Feedback.class);
feedback.setFeedback("Like");
feedback.setCarModel(carModel);
context.commitChanges();
Как видно, мы создаем объекты при помощи ObjectContext
, затем модифицируем их и фиксируем изменения при помощи context.commitChanges()
.
Для выборки сущностей можно использовать API на любой вкус от чистого sql и ejbql до хорошо читаемого API. Полное описание можно найти в документации.
Небольшой пример обычного селекта из базы с использованием Apache Cayenne:
List<CarBrand> carBrans = ObjectSelect.query(CarBrand.class).select(context);
На этом у меня все. Как видно из этого примера, за несколько шагов можно получить боевой ORM, который полностью готов к работе. Надеюсь статья оказалась полезной. С полным примером можно ознакомиться здесь.