Автор оригинала: Marcos Lopez Gonzalez.
1. введение
В этой краткой статье мы рассмотрим использование преобразователей атрибутов, доступных в JPA 2.1, которые, проще говоря, позволяют нам сопоставлять типы JDBC с классами Java.
Мы будем использовать Hibernate 5 в качестве нашей реализации JPA здесь.
2. Создание конвертера
Мы покажем, как реализовать конвертер атрибутов для пользовательского класса Java.
Во – первых, давайте создадим класс PersonName , который будет преобразован позже:
public class PersonName implements Serializable {
private String name;
private String surname;
// getters and setters
}Затем мы добавим атрибут типа Имя человека в класс @Entity :
@Entity(name = "PersonTable")
public class Person {
private PersonName personName;
//...
}Теперь нам нужно создать конвертер, который преобразует атрибут Person Name в столбец базы данных и наоборот. В нашем случае мы преобразуем атрибут в значение String , содержащее поля имени и фамилии.
Для этого мы должны аннотировать наш класс конвертера с помощью @Converter и реализовать интерфейс AttributeConverter . Мы параметризуем интерфейс с типами класса и столбца базы данных в таком порядке:
@Converter public class PersonNameConverter implements AttributeConverter{ private static final String SEPARATOR = ", "; @Override public String convertToDatabaseColumn(PersonName personName) { if (personName == null) { return null; } StringBuilder sb = new StringBuilder(); if (personName.getSurname() != null && !personName.getSurname() .isEmpty()) { sb.append(personName.getSurname()); sb.append(SEPARATOR); } if (personName.getName() != null && !personName.getName().isEmpty()) { sb.append(personName.getName()); } return sb.toString(); } @Override public PersonName convertToEntityAttribute(String dbPersonName) { if (dbPersonName == null || dbPersonName.isEmpty()) { return null; } String[] pieces = dbPersonName.split(SEPARATOR); if (pieces == null || pieces.length == 0) { return null; } PersonName personName = new PersonName(); String firstPiece = !pieces[0].isEmpty() ? pieces[0] : null; if (dbPersonName.contains(SEPARATOR)) { personName.setSurname(firstPiece); if (pieces.length >= 2 && pieces[1] != null && !pieces[1].isEmpty()) { personName.setName(pieces[1]); } } else { personName.setName(firstPiece); } return personName; } }
Обратите внимание, что нам пришлось реализовать 2 метода: convertToDatabaseColumn() и convertToEntityAttribute().
Эти два метода используются для преобразования атрибута в столбец базы данных и наоборот.
3. Использование конвертера
Чтобы использовать наш конвертер, нам просто нужно добавить аннотацию @Convert к атрибуту и указать класс конвертера, который мы хотим использовать :
@Entity(name = "PersonTable")
public class Person {
@Convert(converter = PersonNameConverter.class)
private PersonName personName;
// ...
}Наконец, давайте создадим модульный тест, чтобы убедиться, что он действительно работает.
Для этого мы сначала сохраним объект Person в нашей базе данных:
@Test
public void givenPersonName_whenSaving_thenNameAndSurnameConcat() {
String name = "name";
String surname = "surname";
PersonName personName = new PersonName();
personName.setName(name);
personName.setSurname(surname);
Person person = new Person();
person.setPersonName(personName);
Long id = (Long) session.save(person);
session.flush();
session.clear();
}Затем мы проверим, что имя PersonName было сохранено так, как мы определили его в конвертере, – путем извлечения этого поля из таблицы базы данных:
@Test
public void givenPersonName_whenSaving_thenNameAndSurnameConcat() {
// ...
String dbPersonName = (String) session.createNativeQuery(
"select p.personName from PersonTable p where p.id = :id")
.setParameter("id", id)
.getSingleResult();
assertEquals(surname + ", " + name, dbPersonName);
}Давайте также проверим, что преобразование значения, хранящегося в базе данных, в класс PersonName работает так, как определено в конвертере, написав запрос, который извлекает весь класс Person :
@Test
public void givenPersonName_whenSaving_thenNameAndSurnameConcat() {
// ...
Person dbPerson = session.createNativeQuery(
"select * from PersonTable p where p.id = :id", Person.class)
.setParameter("id", id)
.getSingleResult();
assertEquals(dbPerson.getPersonName()
.getName(), name);
assertEquals(dbPerson.getPersonName()
.getSurname(), surname);
}4. Заключение
В этом кратком руководстве мы показали, как использовать недавно введенные преобразователи атрибутов в JPA 2.1.
Как всегда, полный исходный код примеров доступен на GitHub .