Как отобразить тип объекта Oracle в объекте, используя Spring Data JPA?
Этот вопрос особенно связан с отображением типа объекта Oracle в сущности с использованием Spring Data JPA. Другой вопрос не помог объяснить проблему в деталях.
Итак, здесь ниже приведены подробности:
Я не смог найти информацию, связанную с отображением типа объекта Oracle в объектах сущности с помощью Spring Data JPA ни в Spring Data JPA Reference, ни в каких-либо других результатах поиска.
Сценарий:
Допустим, у меня есть следующий тип Oracle date_typ.
CREATE TYPE date_typ AS OBJECT (
month VARCHAR2(2),
day VARCHAR2(2),
year VARCHAR2(4),
extension VARCHAR2(10),
MEMBER FUNCTION getFullDate RETURN VARCHAR2
);
CREATE TYPE BODY date_typ AS
MAP MEMBER FUNCTION getFullDate RETURN VARCHAR2 AS
BEGIN
return month || day || year;
END getFullDate;
END;
Теперь в таблице базы данных оракула, скажем, REGISTRATION, один из столбцов имеет вышеуказанный date_typ
Column Type
REG_ID VARCHAR2(25) primary key
FIRSTNAME VARCHAR2(30) not null
LASTNAME VARCHAR2(30) not null
MIDDLEINIT VARCHAR2(10)
REQUESTEDDATE DATE_TYP
...
...
Теперь мне нужно сопоставить вышеуказанные столбцы в сущности
@Entity
@Table(name = "REGISTRATION", schema = "accounts")
public class RegistrationEntity {
@Id
@Column(name = "REG_ID")
private String registrationId;
@Column(name = "FIRSTNAME", nullable = false)
private String firstName;
@Column(name = "LASTNAME", nullable = false)
private String lastName;
@Column(name = "MIDDLEINIT")
private String middleInitial;
requestedDate ???
}
Как мне сопоставить requestedDate
к REQUESTEDDATE
столбец DATE_TYP (тип объекта Oracle) в Spring JPA?
Примечания: я использую Hibernate в качестве поставщика сохраняемости.
2 ответа
В этом ответе говорится, что в JPA нет официальной поддержки типов объектов Oracles, но есть поддержка в Eclipse Link. Я предполагаю, что это означает, что в Hibernate нет встроенной поддержки для этого.
Но этот блог описывает, как реализовать UserType
сопоставить класс Java с типом объекта Oracle.
Spring Data на самом деле не участвует в этом, потому что он просто использует реализацию JPA для сопоставления объектов с базой данных. Преобразования и проекции, предлагаемые Spring Data, конвертируют только входные параметры / выходные значения перед их передачей в / после получения их от поставщика JPA.
Вот моя реализация с обновленной версией по ссылке, предоставленной Йенсом Шаудером. Реализация, описанная в ссылке, использует устаревший тип STRUCT и не работает у меня как есть. Это сработало для меня.
Пользовательский тип объекта
create type CUSTOMER_ADDRESS as object
(
STREET_ADDRESS VARCHAR2(50),
CITY VARCHAR2(20)
)
import lombok.Data;
@Data
public class Address {
String streetAddress;
String city;
}
Пользовательский тип:
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;
import java.io.Serializable;
import java.sql.*;
import static java.sql.Types.STRUCT;
/**
* **
* Usage in Entity
* @Column(name="TABLE_NAME", columnDefinition="CUSTOMER_ADDRESS")
* @Type(type= "com.example.demo.AddressType")
* private Address address;
*/
public class AddressType implements UserType {
private static final int SQL_TYPE = STRUCT;
private static final String DB_OBJECT_TYPE = "CUSTOMER_ADDRESS"; //DB custom type name
@Override
public int[] sqlTypes() {
return new int[]{SQL_TYPE};
}
@Override
public Class returnedClass() {
return Address.class;
}
@Override
public Address nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
final Struct struct = (Struct) rs.getObject(names[0]);
if (rs.wasNull()) {
return null;
}
final Address address = new Address();
address.streetAddress = (String) struct.getAttributes()[0];
address.city = (String) struct.getAttributes()[1];
return address;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
if (value != null) {
final Address address = (Address) value;
final Struct address = st.getConnection().createStruct(DB_OBJECT_TYPE,new Object[]{
address.streetAddress,
address.city
});
st.setObject(index, address, SQL_TYPE);
} else {
st.setNull(index, SQL_TYPE, DB_OBJECT_TYPE);
}
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
return ((x == y) || (x != null && y != null && x.equals(y)));
}
@Override
public int hashCode(Object x) throws HibernateException {
return x != null ? x.hashCode() : 0;
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value == null ? null : value;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
Object deepCopy = deepCopy(value);
if (!(deepCopy instanceof Serializable)) {
return (Serializable) deepCopy;
}
return null;
}
@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return deepCopy(cached);
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return deepCopy(original);
}
}