Введение в Apache Cayenne ORM

Введение в 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, чтобы получить в качестве вывода следующий экран:

image

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,, который покажет разработчик моделей:

image

Здесь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 и нажмите «Продолжить»:

image

На следующем экране нам нужно проверить «Использовать примитивные типы Java» следующим образом:

image

Нам также необходимо убедиться, чтоcom.example.apachecayenne.persistent помещается как пакет Java и сохраняется; мы увидим, что файл конфигурации XML был обновлен для своего свойстваdefaultPackage, чтобы соответствовать пакету Java:

image

В каждомObjEntity мы должны указать пакет для подклассов, как показано на следующем изображении, и снова щелкнуть значок“save”:

image

Теперь в меню“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.