Can Hibernate automatically uppercase a column on read/insert via configuration?
We have some columns with data that must always be in uppercase to ensure uniqueness. I was wondering if hibernate can force all such columns to uppercase via some configuration file change?
We actually use a custom UserType for encrypting/decrypting column data for some other table, but I figured that would be overkill just to uppercase everything...
Alternatively, I was thinking about modifying the models such that all getters/setters will uppercase any string coming and going.
The worst(?) case scenario is to modify the Oracle column constraint to ignore ca开发者_Python百科se while checking uniqueness.
Any thoughts?
Much cleaner approach:
@Column(name = "DUMMY")
@ColumnTransformer(read = "UPPER(DUMMY)")
private String dummy
Several solutions:
- Use a database trigger (not via configuration though).
- Modify the getter/setters (not via configuration though).
- Use a
UserType
to convert the attribute to upper case. - Use an interceptor or an event listener.
Solution #1 is transparent for the code but I'm not a big fan of "behind your back" triggers and I don't like to spread business rules everywhere. Solution #3 and #4 are Hibernate dependent (but this might not be an issue though). Solution #2 is the easiest and most portable solution if you can change the code. That would be my choice if this is an option.
I am not aware of any configuration settings to make this possible. However, you could try using an interceptor to fix the data upon insert / update, like:
package interceptor;
import java.io.Serializable;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
public class CustomSaveInterceptor extends EmptyInterceptor {
public boolean onSave(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types)
{
if (entity instanceof MyClass) {
MyClass myInstance = (MyClass)entity;
myInstance.setName(myInstance.getName().toUpperCase());
}
return super.onSave(entity, id, state, propertyNames, types);
}
}
I decided to implement a UserType...it is as close to a hibernate configuration as I can get...here's the code...
package model;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class UpperCaseUserType implements UserType {
private static final int[] TYPES = {Types.VARCHAR};
public int[] sqlTypes() {
return TYPES;
}
public Class returnedClass() {
return String.class;
}
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
}
if (null == x || null == y) {
return false;
}
return new EqualsBuilder().append(x, y).isEquals();
}
public int hashCode(Object o) throws HibernateException {
return new HashCodeBuilder().append(o).toHashCode();
}
public Object nullSafeGet(ResultSet resultSet, String[] strings, Object object) throws HibernateException, SQLException {
return ((String) Hibernate.STRING.nullSafeGet(resultSet, strings[0])).toUpperCase();
}
public void nullSafeSet(PreparedStatement preparedStatement, Object object, int i) throws HibernateException, SQLException {
String string = ((String) object).toUpperCase();
Hibernate.STRING.nullSafeSet(preparedStatement, string, i);
}
public Object deepCopy(Object o) throws HibernateException {
if (null == o) {
return null;
}
return new String(o.toString());
}
public boolean isMutable() {
return false;
}
public Serializable disassemble(Object o) throws HibernateException {
return (String) o;
}
public Object assemble(Serializable serializable, Object o) throws HibernateException {
return serializable;
}
public Object replace(Object o, Object arg1, Object arg2) throws HibernateException {
return o;
}
}
Consider this property element
<property name="serialNumber" type="model.UpperCaseUserType">
<column name="SERIAL_NUMBER" length="20" not-null="true" unique="true" />
</property>
So the reasoning...As hibernate inserts the data, this type will convert the string to uppercase. As hibernate selects data, the same thing happens. The advantage this class has over just changing the bean's get/set to uppercase everything is when I use a Criteria to select on serialNumber. Hibernate will also uppercase my parameter as it will cast/apply the same type as defined in the table configuration.
Therefore, I don't need to remember to manually uppercase all of my search criteria for serial numbers...hibernate takes care of that for me...that's exactly what I'm trying to achieve here!
I have a JUnit that demonstrates all of this stuff, but I think my answer is way too big as it is...
I suggest checking out this page: http://forum.springsource.org/archive/index.php/t-18214.html
It has 3 different ways to do this. I believe the least intrusive way is this:
<property name="upperCaseName" formula="upper(name)" lazy="true"/>
精彩评论