Введение в Apache Cayenne ORM
1. обзор
Apache Cayenne - это библиотека с открытым исходным кодом, распространяемая по лицензии Apache, предоставляющая такие функции, как инструмент моделирования, объектно-реляционное сопоставление, также известное как ORM, для локальных операций сохранения и удаленных служб.
В следующих разделах мы увидим, как взаимодействовать с базой данных MySQL с помощью ORM Apache Cayenne.
2. Maven Зависимости
Для начала нам просто нужно добавить следующие зависимости, чтобы вместе запустить Apache Cayenne и MySQL-коннектор и драйвер 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 вручную (что делается редко) рекомендуется использовать средство моделирования, которое является довольно продвинутым инструментом, поставляемым с дистрибутивом Cayenne.
Он доступен для загрузки с этогоarchive в зависимости от вашей ОС или просто используйте кроссплатформенную версию (JAR), включенную в качестве подключаемого модуля Maven.
В центральном репозитории Maven размещаются последние версииApache Cayenne,his modeler иMySQL Connector.
Затем давайте создадим наш проект с помощьюmvn install и запустим графический интерфейс разработчика моделей с помощью командыmvn cayenne-modeler:run, чтобы получить в качестве вывода следующий экран:
3. Настроить
Чтобы Apache Cayenne нашел правильную локальную базу данных, нам просто нужно заполнить его файл конфигурации правильным драйвером, URL-адресом и пользователем в файлеcayenne-project.xml, расположенном в каталогеresources:
Здесь мы можем видеть, что:
-
Локальная база данных называетсяintro_cayenne
-
Если он еще не создан, Cayenne сделает это за нас.
-
Мы подключимся, используя имя пользователяroot и парольroot (измените его в соответствии с пользователями, зарегистрированными в вашей системе управления базами данных)
Внутри этоXMLPoolingDataSourceFactory, ответственный за загрузку информации о соединении JDBC из ресурса XML, связанного сDataNodeDescriptor.
Помните, что эти параметры относятся к системе управления базами данных и драйверу JDBC, поскольку эта библиотека может поддерживать множество различных баз данных.
У каждого из них есть адаптер, доступный в этом подробномlist. Обратите внимание, что полная документация для версии 4.0 еще не доступна, поэтому мы ссылаемся на предыдущую версию здесь.
4. Картография и дизайн базы данных
4.1. моделирование
Теперь давайте нажмем на“Open Project”, перейдем в папку ресурсов проекта и выберем файлcayenne-project.xml,, который покажет разработчик моделей:
Здесьwe’ve got the choice to either create our mapping structure from an existing databaseor to proceed manually. В этой статье будет рассмотрена статья, использующая средство моделирования и существующую базу данных, чтобы войти в Cayenne и быстро узнать, как это работает.
Давайте посмотрим на нашу базу данныхintro_cayenne, которая имеет отношениеone-to-many между двумя таблицами, поскольку автор может публиковать или владеть множеством статей:
-
author: id (PK) иname
-
article: id (PK), title, content иauthor_id(FK)
Теперь перейдем к «Tools > Reengineer Database Schema», и все наши конфигурации сопоставления заполнятся автоматически. На экране подсказки просто заполните доступную конфигурацию источника данных в файлеcayenne-project.xml и нажмите «Продолжить»:
На следующем экране нам нужно проверить «Использовать примитивные типы Java» следующим образом:
Нам также необходимо убедиться, чтоcom.example.apachecayenne.persistent помещается как пакет Java и сохраняется; мы увидим, что файл конфигурации XML был обновлен для своего свойстваdefaultPackage, чтобы соответствовать пакету Java:
В каждомObjEntity мы должны указать пакет для подклассов, как показано на следующем изображении, и снова щелкнуть значок“save”:
Теперь в меню“Tools > Generate Classes” выберите тип «Standard Persistent Objects»; и на вкладке“Classes” отметьте все классы и нажмите“generate”.
Давайте вернемся к исходному коду, чтобы убедиться, что наши постоянные объекты были успешно сгенерированы, говоря оArticle.java_ and Author.java_.
Обратите внимание, что все эти конфигурации сохраняются в файлеdatamap.map.xml, который также находится в папкеresources.
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, но соответствует нескольким столбцам в базе данных
-
Procedure(<procedure>) - для регистрации хранимой процедуры в базе данных
-
Query(<query>) - модель запроса, используемая для сопоставления запроса в файле конфигурации, не забывая, что мы также можем сделать это в коде
Вот полныеdetails.
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. Удалить все записи класса
Также можно удалить все записи таблицы с помощьюSQLTemplate, здесь мы делаем это после каждого метода тестирования, чтобы всегда иметь базу данных void перед запуском каждого теста:
@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. Заключение
В этом руководстве мы сосредоточились на использовании ORM Apache Cayenne, чтобы легко продемонстрировать, как выполнять операции CRUD с отношениемone-to-many.
Как всегда, исходный код этой статьи можно найти вover on GitHub.