在我正在使用的一些遗留代码中,我有一个包含UserType属性的Hibernate模型,用于表示使用整数进行索引的布尔值。此外,它将'false'存储为Oracle优化的null。
/**
* Data type for a boolean value stored in a NUMBER oracle column. 1 evaluates
* to true, null evaluates to false.
*
* This is designed for oracle indexing, since null values are not indexed.
*
*
*/
public class BooleanUserType implements UserType {
private static final int[] SQL_TYPES = { Types.INTEGER };
public int[] sqlTypes() {
return SQL_TYPES;
}
public Class<?> returnedClass() {
return Boolean.class;
}
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {
Boolean result = false;
resultSet.getInt(names[0]);
if (!resultSet.wasNull()) {
result = true;
}
return result;
}
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index) throws HibernateException, SQLException {
Boolean input = (Boolean) value;
if (input == null || input == false) {
preparedStatement.setNull(index, Types.INTEGER);
} else {
preparedStatement.setInt(index, 1);
}
}
public Object deepCopy(Object value) throws HibernateException {
return value;
}
public boolean isMutable() {
return false;
}
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y)
return true;
if (null == x || null == y)
return false;
return x.equals(y);
}
此BooleanUserType用作此(已编辑)模型的列:
public class CustomString implements Serializable{
private static final long serialVersionUID = -5311205585865001342L;
@Id
@Column(name="custom_string_id")
private Long id;
@Column(name="text")
private String text;
@Column(name="active")
@Type(type="my.org.BooleanUserType") // store false as 'null' -- an Oracle optimization
private Boolean active;
(...)
在保存/更新实体时都会调用nullSafeSet 当必须设置查询参数时
但是,这不是我观察到的行为,因为当我使用active
列的布尔值查询此模型时,没有进行转换,我没有得到预期的结果。
我在DB上保存了一个CustomString对象:
new CustomString(1, "text", Boolean.FALSE);
我使查询无法正常工作:
Criteria c = session.createCriteria(CustomString.class);
c.add(Restrictions.eq("active", Boolean.FALSE));
c.list() // No results!
如果我这样做,它会起作用:
Criteria c = session.createCriteria(CustomString.class);
c.add(Restrictions.isNull("active"));
c.list() // Expected result!
同时使用Boolean.TRUE
而不是FALSE
保存对象,然后查询TRUE
,工作正常。
我在nullSafeSet
方法中添加了一些调试日志行,我可以验证在进行查询时没有调用它。
Hibernate是否应该nullSafeSet
实际调用它,并且某种方式不能按预期工作,或者我有一些我不知道的东西,我应该以不同的方式处理它?</ p>
答案 0 :(得分:0)
仅在插入/更新方案中将对象实际刷新到DB时才会评估基础逻辑nullSafeSet()
逻辑。在构建Critera
查询时,Hibernate将使用@Column
注释来确定列名,但不会自动翻转&#34; = FALSE
&#34;到&#34; is null
&#34;对你而言。
更确切地说,查询的SELECT
部分是由您班级中定义的@Columns
确定的,因此Hibernate将始终运行:
SELECT custom_string_id, text, active FROM [schema].[table_name]
将Restrictions
添加到Criteria
会增加WHERE
个谓词,但在它返回要解析为实例的行之前,它不会利用您的BooleanUserType
逻辑你的实体。
最后,我不确定您指的是哪种Oracle优化,但如果您尝试利用空值从索引中删除的事实,那么您可能不想查询{{ 1}}而不是NULL
,因为它会运行全表扫描。但是,如果您只关心活动(False
)行并且想要有效地弃用/归档非活动行,那么将旧数据设置为True
的方法确实可以获得索引性能提升你指的是。