Bộ chuyển đổi thuộc tính JPA

1. Giới thiệu

Trong bài viết nhanh này, chúng tôi sẽ đề cập đến cách sử dụng Bộ chuyển đổi thuộc tính có sẵn trong JPA 2.1 - nói một cách đơn giản, cho phép chúng tôi ánh xạ các loại JDBC sang các lớp Java.

Chúng tôi sẽ sử dụng Hibernate 5 làm triển khai JPA của chúng tôi ở đây.

2. Tạo công cụ chuyển đổi

Chúng tôi sẽ trình bày cách triển khai bộ chuyển đổi thuộc tính cho một lớp Java tùy chỉnh.

Đầu tiên, hãy tạo một lớp PersonName - lớp này sẽ được chuyển đổi sau:

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

Sau đó, chúng ta sẽ thêm thuộc tính kiểu PersonName vào lớp @Entity :

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

Bây giờ chúng ta cần tạo một bộ chuyển đổi để chuyển đổi thuộc tính PersonName thành một cột cơ sở dữ liệu và ngược lại. Trong trường hợp của chúng tôi, chúng tôi sẽ chuyển đổi thuộc tính thành giá trị Chuỗi chứa cả trường tên và họ.

Để làm như vậy, chúng ta phải chú thích lớp trình chuyển đổi của mình bằng @Converter và triển khai giao diện AttributeConverter . Chúng tôi sẽ tham số hóa giao diện với các loại lớp và cột cơ sở dữ liệu, theo thứ tự đó:

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

Lưu ý rằng chúng ta phải triển khai 2 phương thức: convertToDatabaseColumn ()convertToEntityAttribute ().

Hai phương thức được sử dụng để chuyển đổi từ thuộc tính sang cột cơ sở dữ liệu và ngược lại.

3. Sử dụng Bộ chuyển đổi

Để sử dụng trình chuyển đổi của chúng tôi, chúng tôi chỉ cần thêm chú thích @Convert vào thuộc tính và chỉ định lớp trình chuyển đổi mà chúng tôi muốn sử dụng :

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

Cuối cùng, hãy tạo một bài kiểm tra đơn vị để xem nó thực sự hoạt động.

Để làm như vậy, trước tiên chúng ta sẽ lưu trữ một đối tượng Person trong cơ sở dữ liệu của mình:

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

Tiếp theo, chúng ta sẽ kiểm tra xem PersonName đã được lưu trữ như chúng ta đã xác định nó trong trình chuyển đổi hay chưa - bằng cách truy xuất trường đó từ bảng cơ sở dữ liệu:

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

Cũng hãy kiểm tra xem việc chuyển đổi từ giá trị được lưu trữ trong cơ sở dữ liệu sang lớp PersonName có hoạt động như được định nghĩa trong trình chuyển đổi không bằng cách viết một truy vấn truy xuất toàn bộ lớp 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. Kết luận

Trong hướng dẫn ngắn gọn này, chúng tôi đã chỉ ra cách sử dụng Bộ chuyển đổi thuộc tính mới được giới thiệu trong JPA 2.1.

Như mọi khi, mã nguồn đầy đủ cho các ví dụ có sẵn trên GitHub.