views:

635

answers:

5

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 case while checking uniqueness.

Any thoughts?

+1  A: 

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);
    }
}
Péter Török
I have an interceptor containing other "stuff" that I can drop your idea into...but I don't see writing a bunch of if logic for the dozen or so classes that need some of their fields to be uppercase.
T Reddy
A: 

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"/>
sliver
I may be wrong but I don't think that the formula trick will work for insert or updates (I think that Hibernate treats fomula fields as transient and don't save them in the database).
Pascal Thivent
+2  A: 

Several solutions:

  1. Use a database trigger (not via configuration though).
  2. Modify the getter/setters (not via configuration though).
  3. Use a UserType to convert the attribute to upper case.
  4. 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.

Pascal Thivent
I was leaning towards #2 also, but I was looking for a hibernate configuration that would "just work"...
T Reddy
@T Reddy Nothing like that out of the box AFAIK.
Pascal Thivent
A: 

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

T Reddy
A: 

I need help, I have the fallowing problem: When I try to map a table in my database with a bean in my application using hibernate xml mapping files ...hbm.xml I obtein the fallowing resulteverytime I run the app:

INFO: table not found: especies Initial SessionFactory creation failed.org.hibernate.HibernateException: Missing table: especies

I've realize the problem is that hibernate doesn´t recognize my table because I have it in lowercase in the db. I realize about this because when I change the property hibernate.hbm2ddl.auto (placed in the hibernate.cfg.xml, I have it in validate mode) in create and drop mode it works because it create a new table all in uppercase(included column names) and let the old one in lowercase with no change.

I assume this is something about the hibernate conguration, so...

Here is my question: How can I change the hibernate configuration to understand my lowercase configuration of the db?

Thank and sorry about my english

Diana