1. Обзор
Apache Cayenne -это библиотека с открытым исходным кодом, распространяемая под лицензией Apache, предоставляющая такие функции, как инструмент моделирования, объектно-реляционное отображение, известное как ORM, для локальных операций персистентности и удаленных служб.
В следующих разделах мы рассмотрим, как взаимодействовать с базой данных MySQL с помощью Apache Cayenne ORM.
2. Зависимости Maven
Для начала нам просто нужно добавить следующие зависимости, чтобы вызвать Apache Cayenne и MySQL connector драйвер JDBC вместе для доступа к нашей базе данных intro_cayenne :
org.apache.cayenne cayenne-server 4.0.M5 mysql mysql-connector-java 5.1.44 runtime
Давайте настроим плагин Cayenne modeler, который будет использоваться для проектирования или настройки нашего файла сопоставления, который действует как мост между схемой базы данных и объектом Java:
org.apache.cayenne.plugins maven-cayenne-modeler-plugin 4.0.M5
Вместо того чтобы создавать XML-файл сопоставления вручную (делается редко), рекомендуется использовать modeler, который является довольно продвинутым инструментом, поставляемым вместе с дистрибутивом Cayenne.
Он доступен для загрузки из этого архива в зависимости от вашей операционной системы или просто используйте кросс-платформенную версию (JAR), включенную в качестве плагина Maven.
В центральном репозитории Maven хранятся последние версии Apache Cayenne , his modeler и MySQL Connector .
Далее давайте построим наш проект с помощью mvn install и запустим графический интерфейс modeler с помощью команды mvn cayenne-modeler:run , чтобы получить в качестве вывода этот экран:
3. Настройка
Чтобы заставить Apache Cayenne искать правильную локальную базу данных, нам просто нужно заполнить его конфигурационный файл правильным драйвером, URL-адресом и пользователем в файле cayenne-project.xml находится в каталоге ресурсы :
Здесь мы можем видеть, что:
- Локальная база данных называется intro_cayenne
- Если он еще не создан, Кайенна сделает это за нас
- Мы подключимся, используя имя пользователя root и пароль root (измените его в соответствии с пользователями, зарегистрированными в вашей системе управления базами данных)
Внутренне это XMLPoolingDataSourceFactory ответственный за загрузку информации о соединении JDBC из XML-ресурса, связанного с DataNodeDescriptor .
Имейте в виду, что эти параметры относятся к системе управления базами данных и драйверу JDBC, поскольку эта библиотека может поддерживать множество различных баз данных.
У каждого из них есть адаптер, доступный в этом подробном списке . Обратите внимание, что полная документация для версии 4.0 еще не доступна, поэтому мы ссылаемся на предыдущую версию здесь.
4. Картографирование и Проектирование баз данных
4.1. Моделирование
Давайте теперь нажмем на “Открыть проект” , перейдем в папку ресурсов проекта и выберем файл cayenne-project.xml, моделист покажет это:
Здесь у нас есть выбор: либо создать нашу картографическую структуру из существующей базы данных, либо действовать вручную. Эта статья будет обрабатывать тот, который использует модельер и существующую базу данных, чтобы попасть в Cayenne и быстро узнать, как он работает.
Давайте взглянем на нашу базу данных intro_cayenne , которая имеет отношение один ко многим между двумя таблицами, поскольку автор может публиковать или владеть многими статьями:
- автор: id (PK) и имя
- статья: id (PK), название, содержание и author_id(FK)
Теперь давайте перейдем к ” Tools > Reengineer Database Schema “, и все наши конфигурации отображения будут заполнены автоматически. На экране приглашения просто заполните конфигурацию источника данных, доступную там, в cayenne-project.xml файл и нажмите продолжить:
На следующем экране нам нужно проверить “Использовать примитивные типы Java” следующим образом:
Нам также нужно убедиться, что мы поместили com.baeldung.apache cayenne.persistent как Java-пакет и сохранили его; мы увидим, что XML-файл конфигурации был обновлен для его свойства defaultPackage в соответствии с Java-пакетом:
В каждом ObjEctity мы должны указать пакет для подклассов, как показано на следующем рисунке, и снова нажать на значок “сохранить” :
Теперь в меню “Инструменты > Генерировать классы” выберите ” Стандартные постоянные объекты ” в качестве типа; а на вкладке “Классы” проверьте все классы и нажмите “генерировать” .
Давайте вернемся к исходному коду, чтобы увидеть, что наши постоянные объекты были успешно сгенерированы, говоря о _Article.java и _Author.java .
Обратите внимание, что все эти конфигурации сохраняются в файле datamap.map.xml также находится в папке resources .
4.2. Структура Отображения
Сгенерированный файл сопоставления XML, представленный в папке ресурсов, использует некоторые уникальные теги относительно Apache Cayenne:
- DataNode() – модель базы данных, ее содержимое вся информация, необходимая для подключения к базе данных (имя базы данных, драйвер и учетные данные пользователя)
- DataMap() – это контейнер постоянных сущностей с их отношениями
- DbAttribute() – представляет столбец в таблице базы данных
- DbEntity() – модель одной таблицы базы данных или представления, она может иметь атрибуты DbAttributes и отношения
- ObjEntity() – модель одного персистентного класса java; состоит из атрибутов ObjAttributes, соответствующих свойствам класса сущностей, и отношений ObjRelationships, которые являются свойствами, имеющими тип другой сущности
- Embeddable() – модель класса Java, которая действует как свойство ObjEctity, но соответствует нескольким столбцам в базе данных
- Процедура() – регистрация хранимой процедуры в базе данных
- Query() – модель запроса, используемая для отображения запроса в конфигурационном файле без забывания о том, что мы также можем сделать это в коде
Вот полные подробности .
5. Cayenne API
Единственный оставшийся шаг-использовать API Cayenne для выполнения операций с базой данных с использованием сгенерированных классов, зная, что подклассы наших постоянных классов-это просто лучшая практика, используемая для дальнейшей настройки модели.
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 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. Удалить все Записи Класса
Также можно удалить все записи таблицы с помощью шаблона SQL , здесь мы делаем это после каждого метода тестирования, чтобы всегда иметь пустую базу данных перед запуском каждого теста :
@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 .