1. Обзор
Apache Cayenne — это библиотека с открытым исходным кодом, распространяемая по лицензии Apache, предоставляющая такие функции, как инструмент моделирования, объектно-реляционное сопоставление, также известное как ORM, для операций локального сохранения и удаленных служб.
В следующих разделах мы увидим, как взаимодействовать с базой данных MySQL с помощью Apache Cayenne ORM.
2. Зависимости Maven
Для начала нам просто нужно добавить следующие зависимости, чтобы подключить Apache Cayenne и MySQL к драйверу JDBC для доступа к нашей базе данных intro_cayenne
:
<dependency>
<groupId>org.apache.cayenne</groupId>
<artifactId>cayenne-server</artifactId>
<version>4.0.M5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
<scope>runtime</scope>
</dependency>
Давайте настроим подключаемый модуль Cayenne modeler, который будет использоваться для разработки или настройки нашего файла сопоставления, который действует как мост между схемой базы данных и объектом Java:
<plugin>
<groupId>org.apache.cayenne.plugins</groupId>
<artifactId>maven-cayenne-modeler-plugin</artifactId>
<version>4.0.M5</version>
</plugin>
Вместо создания XML-файла сопоставления вручную (что делается редко) рекомендуется использовать средство моделирования, которое является довольно продвинутым инструментом, входящим в состав дистрибутива Cayenne.
Он доступен для загрузки из этого архива в зависимости от вашей ОС или просто используйте кросс-платформенную версию (JAR), включенную в качестве плагина Maven.
Репозиторий Maven Central содержит последние версии Apache Cayenne , его средства моделирования и MySQL Connector .
Далее, давайте создадим наш проект с mvn install
и запустим графический интерфейс моделлера с помощью команды mvn cayenne-modeler:run
, чтобы получить в качестве вывода этот экран:
3. Настройка
Чтобы заставить Apache Cayenne искать правильную локальную базу данных, нам просто нужно заполнить его файл конфигурации правильным драйвером, URL-адресом и пользователем в файле cayenne-project.xml,
расположенном в каталоге ресурсов :
<?xml version="1.0" encoding="utf-8"?>
<domain project-version="9">
<node name="datanode"
factory
="org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory"
schema-update-strategy
="org.apache.cayenne.access.dbsync.CreateIfNoSchemaStrategy">
<data-source>
<driver value="com.mysql.jdbc.Driver"/>
<url value
="jdbc:mysql://localhost:3306/intro_cayenne;create=true"/>
<connectionPool min="1" max="1"/>
<login userName="root" password="root"/>
</data-source>
</node>
</domain>
Здесь мы можем видеть, что:
- Локальная база данных называется
intro_cayenne.
- Если он еще не создан, Cayenne сделает это за нас
- Мы будем подключаться, используя имя пользователя
root
и парольroot
(измените его в соответствии с пользователями, зарегистрированными в вашей системе управления базой данных)
Внутри XMLPoolingDataSourceFactory
отвечает за загрузку информации о соединении JDBC из ресурса XML, связанного с DataNodeDescriptor
.
Имейте в виду, что эти параметры относятся к системе управления базами данных и драйверу JDBC, поскольку эта библиотека может поддерживать множество различных баз данных.
У каждого из них есть адаптер, доступный в этом подробном списке . Обратите внимание, что полная документация для версии 4.0 еще недоступна, поэтому здесь мы ссылаемся на предыдущую версию.
4. Картирование и дизайн базы данных
4.1. Моделирование
Давайте теперь нажмем «Открыть проект»
, перейдем в папку ресурсов проекта и выберем файл cayenne-project.xml,
моделлер покажет это:
Здесь у нас есть выбор: либо создать нашу структуру сопоставления из существующей базы данных , либо продолжить работу вручную. В этой статье рассматривается тот, кто использует модельер и существующую базу данных, чтобы войти в Cayenne и быстро узнать, как это работает.
Давайте взглянем на нашу базу данных intro_cayenne
, которая имеет отношение « один ко многим
» между двумя таблицами, поскольку автор может публиковать или владеть многими статьями:
автор: id (PK)
иимя
статья: id (PK), title, content
иauthor_id (FK)
Теперь давайте перейдем к « Инструменты> Реинжиниринг схемы базы данных
», и все наши конфигурации сопоставления будут заполнены автоматически. На экране подсказки просто заполните конфигурацию источника данных, доступную там, в файле cayenne-project.xml
, и нажмите «Продолжить»:
На следующем экране нам нужно проверить «Использовать примитивные типы Java» следующим образом:
Нам также необходимо поместить com.foreach.apachecayenne.persistent
в качестве пакета Java и сохранить его; мы увидим, что файл конфигурации XML был обновлен для его свойства defaultPackage
, чтобы соответствовать пакету Java:
В каждом ObjEntity
мы должны указать пакет для подклассов, как показано на следующем изображении, и снова щелкнуть значок «Сохранить» :
Теперь в меню «Инструменты > Создать классы»
выберите « Стандартные постоянные объекты
» в качестве типа; и на вкладке «Классы»
отметьте все классы и нажмите «Создать»
.
Вернемся к исходному коду, чтобы увидеть, что наши постоянные объекты были успешно сгенерированы, говоря о _Article.java
и _Author.java
.
Обратите внимание, что все эти конфигурации сохраняются в файле datamap.map.xml
, который также находится в папке ресурсов .
4.2. Структура отображения
Сгенерированный файл сопоставления XML, представленный в папке ресурсов, использует некоторые уникальные теги относительно Apache Cayenne:
DataNode(<node>)
— модель базы данных, ее содержимое, вся информация, необходимая для подключения к базе данных (имя базы данных, драйвер и учетные данные пользователя).DataMap(<data-map>)
— это контейнер постоянных сущностей с их отношениямиDbAttribute(<db-attribute>)
— представляет столбец в таблице базы данных.DbEntity(<db-entity>)
— модель отдельной таблицы или представления базы данных, может иметь DbAttributes и отношенияObjEntity(<obj-entity>)
— модель одного персистентного java-класса; состоит из ObjAttributes, которые соответствуют свойствам класса сущностей, и ObjRelationships, которые являются свойствами, имеющими тип другой сущностиEmbeddable(<embeddable>)
— модель класса Java, которая действует как свойство ObjEntity, но соответствует нескольким столбцам в базе данных.Процедура(<процедура>)
– для регистрации хранимой процедуры в базе данныхQuery(<query>)
— модель запроса, используемая для сопоставления запроса в файле конфигурации, не забывая, что мы также можем сделать это в коде.
Вот полная информация .
5. Кайенский API
Единственный оставшийся шаг — использовать Cayenne API для выполнения операций с базой данных с использованием сгенерированных классов, зная, что создание подклассов для наших постоянных классов — это просто передовая практика, используемая для последующей настройки модели.
5.1. Создание объекта
Здесь мы просто сохраняем объект Author
и позже проверяем, что в базе данных есть только одна запись этого типа:
@Test
public void whenInsert_thenWeGetOneRecordInTheDatabase() {
Author author = context.newObject(Author.class);
author.setName("Paul");
context.commitChanges();
long records = ObjectSelect.dataRowQuery(Author.class)
.selectCount(context);
assertEquals(1, records);
}
5.2. Чтение объекта
После сохранения Author
мы просто выбираем его среди других с помощью простого запроса по определенному свойству:
@Test
public void whenInsert_andQueryByFirstName_thenWeGetTheAuthor() {
Author author = context.newObject(Author.class);
author.setName("Paul");
context.commitChanges();
Author expectedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Paul"))
.selectOne(context);
assertEquals("Paul", expectedAuthor.getName());
}
5.3. Получение всех записей класса
Мы собираемся сохранить двух авторов и получить коллекцию объектов авторов, чтобы убедиться, что сохранены только эти два:
@Test
public void whenInsert_andQueryAll_thenWeGetTwoAuthors() {
Author firstAuthor = context.newObject(Author.class);
firstAuthor.setName("Paul");
Author secondAuthor = context.newObject(Author.class);
secondAuthor.setName("Ludovic");
context.commitChanges();
List<Author> authors = ObjectSelect
.query(Author.class)
.select(context);
assertEquals(2, authors.size());
}
5.4. Обновление объекта
Процесс обновления также прост, но нам нужно сначала получить желаемый объект, прежде чем изменять его свойства и применять его к базе данных:
@Test
public void whenUpdating_thenWeGetAnUpatedeAuthor() {
Author author = context.newObject(Author.class);
author.setName("Paul");
context.commitChanges();
Author expectedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Paul"))
.selectOne(context);
expectedAuthor.setName("Garcia");
context.commitChanges();
assertEquals(author.getName(), expectedAuthor.getName());
}
5.5. Прикрепление объекта
Мы можем назначить статью автору:
@Test
public void whenAttachingToArticle_thenTheRelationIsMade() {
Author author = context.newObject(Author.class);
author.setName("Paul");
Article article = context.newObject(Article.class);
article.setTitle("My post title");
article.setContent("The content");
article.setAuthor(author);
context.commitChanges();
Author expectedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Smith"))
.selectOne(context);
Article expectedArticle = (expectedAuthor.getArticles()).get(0);
assertEquals(article.getTitle(), expectedArticle.getTitle());
}
5.6. Удаление объекта
Удаление сохраненного объекта полностью удаляет его из базы данных, после чего в результате запроса мы увидим null :
@Test
public void whenDeleting_thenWeLostHisDetails() {
Author author = context.newObject(Author.class);
author.setName("Paul");
context.commitChanges();
Author savedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Paul"))
.selectOne(context);
if(savedAuthor != null) {
context.deleteObjects(author);
context.commitChanges();
}
Author expectedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Paul"))
.selectOne(context);
assertNull(expectedAuthor);
}
5.7. Удалить все записи класса
Также можно удалить все записи таблицы с помощью SQLTemplate
, здесь мы делаем это после каждого метода тестирования, чтобы всегда иметь пустую базу данных перед запуском каждого теста :
@After
public void deleteAllRecords() {
SQLTemplate deleteArticles = new SQLTemplate(
Article.class, "delete from article");
SQLTemplate deleteAuthors = new SQLTemplate(
Author.class, "delete from author");
context.performGenericQuery(deleteArticles);
context.performGenericQuery(deleteAuthors);
}
6. Заключение
В этом руководстве мы сосредоточились на использовании Apache Cayenne ORM, чтобы легко продемонстрировать, как выполнять операции CRUD с отношением « один ко многим
».
Как всегда, исходный код этой статьи можно найти на GitHub .