Статьи

Используйте ModelMapper и jOOQ для восстановления контроля над вашей моделью домена

Одна из вещей, в которой Hibernate достаточно хорош, это CRUD, то есть сохранение графов объектов в базе данных. Это особенно верно, если ваше приложение работает в контексте, управляемом моделью домена Java. Конечно, ваши модели должны придерживаться стандартов, установленных JPA / Hibernate. То же самое относится к отображению данных на основе реляционных моделей в графы сложных объектов в памяти. Опять же, вам придется придерживаться стандартов, установленных JPA / Hibernate.

Если вы работаете с довольно сложными реляционными моделями, отображая данные на довольно сложные доменные модели, то вам может потребоваться вернуть контроль над процессом отображения, поскольку автоматическое отображение вызовет больше головной боли, чем решит проблемы. Интересный подход был недавно показан на   веб-сайте ModelMapper в качестве  примера интеграции  с  jOOQ . (обратите внимание, есть также  пример интеграции  с  JDBI ). С разрешения автора Джонатана Хальтермана я привожу этот интересный пример:

Интеграция jOOQ

Интеграция ModelMapper с jOOQ позволяет сопоставить запись jOOQ   с JavaBean.

Настроить

Для начала добавьте  modelmapper-jooq зависимость Maven в ваш проект:

<dependency>
  <groupId>org.modelmapper</groupId>
  <artifactId>modelmapper</artifactId>
  <version>0.6.1</version>
</dependency>
<dependency>
  <groupId>org.modelmapper</groupId>
  <artifactId>modelmapper-jooq</artifactId>
  <version>0.6.1</version>
</dependency>

Затем настройте ModelMapper для поддержки RecordValueReader, который позволяет считывать и отображать значения из записи jOOQ  :

modelMapper.getConfiguration()
           .addValueReader(new RecordValueReader());

Пример сопоставления

Теперь давайте рассмотрим пример отображения записи jOOQ в JavaBean. Рассмотрим следующую запись, представляющую заказ:

номер заказа Пользовательский ИД customer_address_street customer_address_city
345 678 123 Main Street SF

Возможно, нам потребуется отобразить это на более сложную объектную модель:

// Assume getters and setters are present
 
public class Order {
  private int id;
  private Customer customer;
}
 
public class Customer {
  private Address address;
}
 
public class Address {
  private String street;
  private String city;
}

Поскольку в полях исходной записи в этом примере используется соглашение об именах подчеркивания, нам нужно настроить ModelMapper для токенизации имен свойств источника по подчеркиванию:

modelMapper
  .getConfiguration()
  .setSourceNameTokenizer(NameTokenizers.UNDERSCORE);

С этим набором сопоставление Записи заказа с объектом Заказа просто:

Order order = 
  modelMapper.map(orderRecord, Order.class);

И мы можем утверждать, что значения отображаются в соответствии с ожиданиями:

assertEquals(456, order.getId());
assertEquals(789, order.getCustomer().getId());
assertEquals("123 Main Street",
             order.getCustomer()
                  .getAddress()
                  .getStreet());
assertEquals("SF",
             order.getCustomer()
                  .getAddress()
                  .getCity());

Явное отображение

Хотя ModelMapper сделает все возможное, чтобы неявно сопоставить значения Record со свойствами назначения, иногда вам может понадобиться явно определить сопоставления между свойствами.

Давайте сопоставим наши записи  customer_address_street с  Order.customer.address.street:

PropertyMap<Record, Order> orderMap = 
  new PropertyMap<Record, Order>() {
  protected void configure() {
    map(source("customer_address_street"))
        .getCustomer()
        .getAddress()
        .setStreet(null);
  }
};

Затем мы можем добавить отображение в наш  ModelMapper экземпляр для  orderRecord:

modelMapper.createTypeMap(orderRecord, Order.class)
           .addMappings(orderMap);

Что стоит отметить

ModelMapper поддерживает  TypeMap  для каждого типа источника и назначения, содержащий сопоставления между двумя типами. Для «универсальных» типов, таких как Запись, это может быть проблематично, поскольку структура Записи может варьироваться. Чтобы различать структурно разные записи, которые отображаются на один и тот же тип назначения, мы можем предоставить  имя карты типов  для ModelMapper.

Продолжая приведенный выше пример, давайте сопоставим еще одну запись Order, с другой структурой, с тем же классом Order:

номер заказа order_customer_id order_customer_address_street order_customer_address_city
444 777 123 Main Street Луизиана

Сопоставить эту запись с порядком очень просто, но нам нужно предоставить  имя карты типов,  чтобы отличить это сопоставление записи с порядком от предыдущего безымянного сопоставления:

Order order = modelMapper.map(
    longOrderRecord, Order.class, "long");

Пример взят из: 
http://modelmapper.org/user-manual/jooq-integration/

Больше примеров

Выбирая ModelMapper, вы не просто выбираете API для отображения реляционных данных в вашей доменной модели. ModelMapper предназначен для произвольного преобразования модели, что может сделать его стратегическим выбором для вашего стека.

Проверьте этот чудесный камень с открытым исходным кодом на  сайте ModelMapper .