Issue
Can I somehow modify the way Hibernate binds parameters to the query?
For example, I want hibernate to use OracleResultSet.setFixedChar() when executing on an string column, instead of rs.setString() when executing a JPA query via Spring data.
This is how I would do it without Hibernate:
try(PreparedStatement ps = con.executeQuery("...")) {
if(ps.isWrapped(OraclePreparedStatement.class) {
ps.unwrap(OraclePreparedStatement.class).setFixedCHAR(0, myStringField);
} else {
ps.setString(0, myStringField);
}
try(ResultSet rs = ps.getResultSet()) {
while(rs.next()) {
... do stuff ...
}
}
}
Repository method (Spring data JPA):
List<Object> findByMyStringField(String myStringField);
How can I influence how Hibernate binds my variable. With the above example setString is used always.
As background: the problem is that all our Legacy DB's use CHAR columns and not VARCHAR2, so we have to deal with whitespace and setFixedCHAR should do exactly what we would want.
Solution
Found an solution by implementing a SqlTypeDescriptor & Custom Dialect:
@Autowired
private DataSource source;
@Bean
public HibernateJpaVendorAdapter getHibernateJPAVendorAdapter() {
return new CustomHibernateJpaVendorAdaptor();
}
private static class CustomHibernateJpaVendorAdaptor extends HibernateJpaVendorAdapter {
@Override
protected Class<?> determineDatabaseDialectClass(Database database) {
// if HSQL is copied from Spring Sourcecode to keep everything the same
if (Database.HSQL.equals(database)) {
return CustomHsqlDialect.class;
}
try {
if (source.isWrapperFor(OracleDataSource.class)) {
return CustomOracleDialect.class;
}
} catch (SQLException e) {
}
return super.determineDatabaseDialectClass(database);
}
private class CustomHsqlDialect extends HSQLDialect {
public CustomHsqlDialect() {
registerColumnType(Types.BOOLEAN, "boolean");
registerHibernateType(Types.BOOLEAN, "boolean");
}
}
}
@NoArgsConstructor
public static class CustomOracleDialect extends Oracle12cDialect {
private static final OracleCharFix INSTANCE = new OracleCharFix();
@Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(final int sqlCode) {
switch (sqlCode) {
case Types.VARCHAR:
return INSTANCE;
default:
return super.getSqlTypeDescriptorOverride(sqlCode);
}
}
}
@Slf4j
private static class OracleCharFix extends CharTypeDescriptor {
@Override
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<>(javaTypeDescriptor, this) {
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
if (st.isWrapperFor(OraclePreparedStatement.class)) {
OraclePreparedStatement ops = st.unwrap(OraclePreparedStatement.class);
if (ops.getParameterMetaData().getParameterType(index) == Types.CHAR) {
ops.setFixedCHAR(index, javaTypeDescriptor.unwrap(value, String.class, options));
} else {
st.setString(index, javaTypeDescriptor.unwrap(value, String.class, options));
}
} else {
st.setString(index, javaTypeDescriptor.unwrap(value, String.class, options));
}
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
//Is nolonger used by Hibernate in the current Version
st.setString(name, javaTypeDescriptor.unwrap(value, String.class, options));
}
private boolean checkIfCHARByName(ResultSetMetaData metadata, String name)
throws SQLException {
for (int i = 1; i <= metadata.getColumnCount(); i++) {
if (metadata.getColumnType(i) == Types.CHAR && Objects.equals(metadata.getColumnName(i), name)) {
return true;
}
}
return false;
}
};
}
Answered By - Chris Answer Checked By - Mildred Charles (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.