Hi,
I have three columns in my database called newValueDate, newValueString and newValueInteger. I mapped all three columns to one property called newValue using a CompositeUserType. Saving and reading the values from the database works fine, as long as I do not use the property newValue for searching the entity in the database. If I do so, I got an empty result, because Hibernate executes a query like:
where newValueDate = NULL and newValueString = NULL and newValueInteger = 5.
Because I have to use oracle as a RDBMS, this query is wrong. Oracle needs newValue is null instead of newValue = null.
Can anybody please tell me, why hibernate or JDBC creates here a wrong SQL-query?
Following my CompositeUserType Implementation:
Code:
package de.andreasgrund.core.model.common.usertypes;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Date;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.Type;
import org.hibernate.usertype.CompositeUserType;
import org.joda.time.DateTime;
import de.andreasgrund.core.model.common.AttributeWert;
import de.andreasgrund.core.model.common.AttributeWertDate;
import de.andreasgrund.core.model.common.AttributeWertInteger;
import de.andreasgrund.core.model.common.AttributeWertString;
public class AttributeWertCompositeUserType implements CompositeUserType {
private static final Log LOG = LogFactory.getLog(AttributeWertCompositeUserType.class);
private static final String[] PROPERTY_NAMES = { "neuerWert", "neuerWertDate", "neuerWertInteger" };
private static final Type[] PROPERTY_TYPES = { Hibernate.STRING, Hibernate.DATE, Hibernate.INTEGER };
@Override
public String[] getPropertyNames() {
return PROPERTY_NAMES;
}
@Override
public Type[] getPropertyTypes() {
return PROPERTY_TYPES;
}
@Override
public Object getPropertyValue(Object component, int property) throws HibernateException {
if (component instanceof AttributeWertString && property == 0) {
// die Property mit der Nummer 0 nimmt immer die String-Werte auf
return ((AttributeWertString) component).getInternal();
} else if (component instanceof AttributeWertDate && property == 1) {
// die Property mit der Nummer 1 nimmt immer die Date-Werte auf
return ((AttributeWertDate) component).getInternal();
} else if (component instanceof AttributeWertInteger && property == 2) {
// die Property mit der Nummer 2 nimmt immer die Integer-Werte auf
return ((AttributeWertInteger) component).getInternal();
} else {
return null;
}
}
@Override
public void setPropertyValue(Object component, int property, Object value) throws HibernateException {
throw new UnsupportedOperationException("wird nicht unterstuetzt");
}
@Override
public Class<?> returnedClass() {
return AttributeWert.class;
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == null) {
return y == null;
} else {
return x.equals(y);
}
}
@Override
public int hashCode(Object x) throws HibernateException {
if (x == null) {
return 0;
} else {
return x.hashCode();
}
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
for (int i = 0; i < names.length; i++) {
Object object = rs.getObject(names[i]);
if (object instanceof String) {
return AttributeWertString.valueOf((String) object);
} else if (object instanceof Date) {
return AttributeWertDate.valueOf(new DateTime(((Date) object).getTime()));
} else if (object instanceof BigDecimal) {
return AttributeWertInteger.valueOf(((BigDecimal) object).intValue());
}
}
return null;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
if (value instanceof AttributeWertString) {
AttributeWertString wert = (AttributeWertString) value;
Hibernate.STRING.set(st, wert.getInternal(), index);
st.setNull(index + 1, Types.DATE);
st.setNull(index + 2, Types.INTEGER);
} else if (value instanceof AttributeWertDate) {
AttributeWertDate wert = (AttributeWertDate) value;
st.setNull(index, Types.VARCHAR);
Hibernate.DATE.set(st, wert.getInternal().toDate(), index + 1);
st.setNull(index + 2, Types.INTEGER);
} else if (value instanceof AttributeWertInteger) {
AttributeWertInteger wert = (AttributeWertInteger) value;
// Hibernate.STRING.set(st, null, index);
st.setNull(index, Types.VARCHAR);
st.setNull(index + 1, Types.DATE);
// st.setDate(index + 1, null);
Hibernate.INTEGER.set(st, wert.getInternal(), index + 2);
} else {
// sollte der uebergebene Wert weder ein AttributeWert fuer Integer, noch fuer Date oder String sein, tue
// einfach nichts.
return;
}
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Serializable disassemble(Object value, SessionImplementor session) throws HibernateException {
return (Serializable) value;
}
@Override
public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException {
return cached;
}
@Override
public Object replace(Object original, Object target, SessionImplementor session, Object owner)
throws HibernateException {
return original;
}
}
The classes AttributeWertString, AttributeWertInteger and AttributeWertDate are just simple Delegates to a String, Integer or joda.DateTime Instance. And AttributeWert is the parent interface for these three classes.
Thanks for your help and kind regards,
Andreas Grund