我有一个hibernate映射的Java对象JKL
,它充满了一堆普通的hibernate-mappable字段(如字符串和整数)。
我添加了一个新的嵌入字段(它位于同一个表中 - 而不是映射),asdf
,这是一个fj.data.Option<ASDF>
。我已经明确表示这个字段实际上可能不包含任何内容(而不是每次访问时都必须处理null
)。
如何在JKL.hbm.xml
文件中设置映射?我希望hibernate在检索对象时自动将数据库中的null
转换为none
fj.data.Option<ASDF>
。它还应该将ASDF
的非空实例转换为some
的{{1}}。我还有其他的诡计吗?谢谢。
答案 0 :(得分:12)
我建议在访问器(getter和setter)中引入FunctionalJava的Option
,同时让Hibernate处理一个允许null
的简单java字段。
例如,对于可选的Integer
字段:
// SQL
CREATE TABLE `JKL` (
`JKL_ID` INTEGER PRIMARY KEY,
`MY_FIELD` INTEGER DEFAULT NULL
)
您可以直接映射Hibernate私有字段:
// Java
@Column(nullable = true)
private Integer myField;
然后,您可以在访问者边界引入Option
:
// Java
public fj.data.Option<Integer> getMyField() {
return fj.data.Option.fromNull(myField);
}
public void setMyField(fj.data.Option<Integer> value) {
myField = value.toNull();
}
这是否适合您的需求?
答案 1 :(得分:2)
您可以使用Hibernate的自定义映射类型。文档为here。以下是Hibernate映射的mapping Scala's Option的类似示例。
简单地说,您需要扩展org.hibernate.UserType
接口。您还可以使用JKL
类型的子类型创建泛型类型的基类,类似于您在Scala示例中看到的类型。
答案 2 :(得分:0)
我认为使用getter/setter
更简单,但这是我做的工作的一个例子:
(它适用于数字和字符串,但不适用于日期(带@Temporal
注释的错误))。
import com.cestpasdur.helpers.PredicateHelper;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
import org.joda.time.DateTime;
import java.io.Serializable;
import java.sql.*;
public class OptionUserType implements UserType {
@Override
public int[] sqlTypes() {
return new int[]{
Types.NULL
};
}
@Override
public Class returnedClass() {
return Optional.class;
}
@Override
public boolean equals(Object o, Object o2) throws HibernateException {
return ObjectUtils.equals(o, o2);
}
@Override
public int hashCode(Object o) throws HibernateException {
assert (o != null);
return o.hashCode();
}
@Override
public Optional<? extends Object> nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
return Optional.fromNullable(rs.getObject(names[0]));
}
@VisibleForTesting
void handleDate(PreparedStatement st, Date value, int index) throws SQLException {
st.setDate(index, value);
}
@VisibleForTesting
void handleNumber(PreparedStatement st, String stringValue, int index) throws SQLException {
Double doubleValue = Double.valueOf(stringValue);
st.setDouble(index, doubleValue);
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index) throws SQLException {
if (value != null) {
if (value instanceof Optional) {
Optional optionalValue = (Optional) value;
if (optionalValue.isPresent()) {
String stringValue = String.valueOf(optionalValue.get());
if (StringUtils.isNotBlank(stringValue)) {
if (PredicateHelper.IS_DATE_PREDICATE.apply(stringValue)) {
handleDate(st, new Date(DateTime.parse(stringValue).getMillis()), index);
} else if (StringUtils.isNumeric(stringValue)) {
handleNumber(st, stringValue, index);
} else {
st.setString(index, optionalValue.get().toString());
}
} else {
st.setString(index, null);
}
} else {
System.out.println("else Some");
}
} else {
//TODO replace with Preconditions guava
throw new IllegalArgumentException(value + " is not implemented");
}
} else {
st.setString(index, null);
}
}
@Override
public Object deepCopy(Object o) throws HibernateException {
return o;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Serializable disassemble(Object o) throws HibernateException {
return (Serializable) o;
}
@Override
public Object assemble(Serializable serializable, Object o) throws HibernateException {
return serializable;
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
}