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(); Listauthors = 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 .