JPA-Attributkonverter

1. Einleitung

In diesem kurzen Artikel werden wir die Verwendung der in JPA 2.1 verfügbaren Attributkonverter behandeln, mit denen wir einfach ausgedrückt JDBC-Typen Java-Klassen zuordnen können.

Wir werden Hibernate 5 hier als JPA-Implementierung verwenden.

2. Erstellen eines Konverters

Wir werden zeigen, wie ein Attributkonverter für eine benutzerdefinierte Java-Klasse implementiert wird.

Erstellen wir zunächst eine PersonName- Klasse, die später konvertiert wird:

public class PersonName implements Serializable { private String name; private String surname; // getters and setters }

Dann werden wir ein Attribut vom Typ hinzufügen Personname zu einer @Entity Klasse:

@Entity(name = "PersonTable") public class Person { private PersonName personName; //... }

Jetzt müssen wir einen Konverter erstellen, der das PersonName- Attribut in eine Datenbankspalte umwandelt und umgekehrt. In unserem Fall konvertieren wir das Attribut in einen String- Wert, der sowohl Vor- als auch Nachnamenfelder enthält.

Dazu müssen wir unsere Konverterklasse mit @Converter kommentieren und die AttributeConverter- Schnittstelle implementieren . Wir werden die Schnittstelle mit den Typen der Klasse und der Datenbankspalte in dieser Reihenfolge parametrisieren:

@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; } }

Beachten Sie, dass wir zwei Methoden implementieren mussten: convertToDatabaseColumn () und convertToEntityAttribute ().

Die beiden Methoden werden verwendet, um vom Attribut in eine Datenbankspalte zu konvertieren und umgekehrt.

3. Verwenden des Konverters

Um unseren Konverter zu verwenden, müssen wir nur die Annotation @Convert zum Attribut hinzufügen und die Konverterklasse angeben, die wir verwenden möchten :

@Entity(name = "PersonTable") public class Person { @Convert(converter = PersonNameConverter.class) private PersonName personName; // ... }

Lassen Sie uns abschließend einen Komponententest erstellen, um festzustellen, ob er wirklich funktioniert.

Dazu speichern wir zunächst ein Personenobjekt in unserer Datenbank:

@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(); }

Als Nächstes testen wir, ob der Personenname so gespeichert wurde, wie wir ihn im Konverter definiert haben - indem wir dieses Feld aus der Datenbanktabelle abrufen :

@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); }

Testen Sie außerdem, ob die Konvertierung von dem in der Datenbank gespeicherten Wert in die PersonName- Klasse wie im Konverter definiert funktioniert, indem Sie eine Abfrage schreiben, die die gesamte Person- Klasse abruft :

@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. Fazit

In diesem kurzen Tutorial haben wir gezeigt, wie die neu eingeführten Attributkonverter in JPA 2.1 verwendet werden.

Wie immer ist der vollständige Quellcode für die Beispiele auf GitHub verfügbar.