Статьи

Расширение ваших JPA POJO

Расширяемость является важной характеристикой во многих архитектурах. Это показатель того, насколько легко (или сложно)
это добавить или изменить функциональность, не влияя на существующую функциональность ядра системы.

Давайте возьмем простой пример. Предположим, у вашей компании есть основной продукт для отслеживания всех пользователей в спортивном клубе. В вашей архитектуре продукта у вас есть модель предметной области, представленная JPA POJO. Модель предметной области содержит много POJO, включая, конечно, User POJO.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.alex.staveley.persistence
/**
 * User entity.  Represents Users in the Sports Club.
 * * Note: The SQL to generate a table for this in MySQL is:
 *
 * CREATE TABLE USER (ID INT NOT NULL auto_increment, NAME varchar(255) NOT NULL,
 *  PRIMARY KEY (ID)) ENGINE=InnoDB;
 */
@Entity
public class User {
    /* Surrogate Key - automatically generated by DB. */
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Id
    private int id;
  
    private String name;
 
    public int getId() {
        return id;
    }
  
    public void setName(String name) {
        this.name=name;
    }
  
    public String getName() {
        return name;
    }
}

Некоторым покупателям нравится ваш продукт, но перед покупкой им необходимо выполнить некоторые настройки. Например,
один клиент хочет, чтобы атрибут места рождения был добавлен к пользователю и хотел, чтобы это сохранялось Логическое место для этого атрибута — конечно — в пользовательском POJO, но ни один другой клиент не хочет этот атрибут. Ну так что ты делаешь?

Вы делаете определенный класс User только для этого клиента, а затем меняете его только для них? Что происходит
когда вы меняете класс Product User? Что произойдет, если другой клиент хочет другую настройку?
Или передумает? Вы чувствуете, что все станет грязно?

К счастью, одна реализация JPA: Eclipselink помогает здесь. Выпуск 2.3 (доступный с июня 2011 года, последний выпуск — техническое обслуживание 2.3.2, выпущенное совсем недавно, 9 декабря 2011 года) включает в себя некоторые функции, которые отлично подходят для сценариев этого типа. Давайте уточним. Просто добавив аннотацию @VirtualAccessmethods Eclipselink к POJO, мы сообщаем Eclipselink, что POJO может иметь некоторые дополнительные ( также известные как виртуальные ) атрибуты. Вам не нужно указывать какие-либо из этих дополнительных атрибутов в коде, иначе они не будут очень виртуальными ! Вам просто нужно указать универсальный метод получения и установки для обслуживания их получения и настройки. Вам также нужно где-то хранить их в памяти, что-то вроде старого доброго hashmap, что, конечно, должно быть временным, потому что мы не сохраняем сам hashmap. Примечание: их не нужно хранить в HashMap, это просто популярный выбор!

Давайте посмотрим на нашего обновленного пользователя, который теперь расширяем!

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Entity
@VirtualAccessMethods
public class User {
    /* Surrogate Key - automatically generated by DB. */
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Id
    private int id;
   
    private String name;
   
    @Transient
    private Map<String, Object> extensions = new HashMap();
  
    public int getId() {
        return id;
    }
   
    public void setName(String name) {
        this.name=name;
    }
   
    public String getName() {
        return name;
    }
   
    public <t> T get(String name) {
        return (T) extensions.get(name);
    }
   
    public Object set(String name, Object value) {
        return extensions.put(name, value);
    }
}

Так это все? Ну, есть немного больше магии. Вы должны рассказать eclipselink о ваших дополнительных атрибутах. Более конкретно: каковы их имена и типы данных.
Вы делаете это путем обновления вашего eclipselink-orm.xml, который находится в той же папке META-INF, в которой находится файл persistent.xml.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
    version="2.1">
  
    <entity class="com.alex.staveley.persistence.User">
        <attributes>
     <basic name="thebirthplace" attribute-type="String" access="VIRTUAL">
                <column name="birthplace"/>
                <access-methods get-method="get" set-method="set"/>
            </basic>
        </attributes>
    </entity>
</entity-mappings>

Теперь эта конфигурация просто утверждает, что у сущности User есть дополнительный атрибут, который в java — «thebirthplace», и он является виртуальным. Это означает, что он не определен явно в POJO, но если бы мы отлаживали вещи, мы увидели бы атрибут с именем «thebirthplace» в памяти.

Эта конфигурация также утверждает, что соответствующий столбец базы данных для атрибута является местом рождения.
И eclipselink может получить и установить этот метод, используя общие методы get / set.

Вы хотите проверить это?

Хорошо добавьте столбец в таблицу базы данных. В MySql это будет:

изменить таблицу пользователя добавить столбец место рождения varchar (64)

Затем запустите этот простой тест:

01
02
03
04
05
06
07
08
09
10
@Test
public void testCreateUser() {
    User user = new User();
    user.setName("User1Name");
    user.set("thebirthplace", "donabate");
    entitymanager.getTransaction().begin();
    entitymanager.persist(user);
    entitymanager.getTransaction().commit();
    entitymanager.close();
}

Так что теперь мы можем иметь один пользовательский POJO в нашем коде продукта, который является расширяемым. Каждый клиент может иметь свои собственные атрибуты, добавленные к пользователю — по своему усмотрению. И, конечно же, каждый клиент отделен от
всех остальных клиентов очень легко, просто убедившись, что расширения каждого клиента находятся в определенном файле eclipslink-orm.xml. Помните, что вы можете называть эти файлы по своему усмотрению, и если вы не используете имена по умолчанию, просто обновите файл persistence.xml, чтобы указать, какие имена вы используете .

Этот подход означает, что когда мы хотим обновить Пользователя в нашем продукте, нам нужно обновить только один и только Пользователь POJO ( потому что мы убедились, что есть только один ). Но когда необходимо добавить определенные атрибуты для конкретных клиентов, мы не затрагиваем код POJO пользователя. Мы просто вносим изменения в XML и не должны ничего перекомпилировать из основного продукта. И, конечно же, в любое время легко увидеть, какие настройки есть у любого клиента, просто взглянув на соответствующий файл eclipselink-orm.file.

Вы Ха Счастливого продолжения!

Рекомендации:

  1. Расширение ваших JPA POJO от нашего партнера JCG Алекса Стейвли в техническом блоге Дублина
  2. http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Extensible_Entities
  3. http://www.eclipse.org/eclipselink/

Статьи по Теме :