我使用Hibernate作为我的JPA提供程序,它连接到Progress数据库。当持久化NaN值时,会导致很多问题 - 它会阻止在某些情况下读取行。有没有办法挂钩标准双类型持久性将NaN(可能是+和 - 无穷大)转换为不同的值?如果NaN或无穷大信息丢失无关紧要,我只想要一个可读的行!
我知道我可以这样做:
@Column(name = "doubleColumn")
public double getDoubleColumn() {
return PersistedDouble.convert(doubleColumn);
}
但我担心维护,因为必须为映射到数据库的任何双打手动添加维护。
答案 0 :(得分:3)
我对此的第一印象是寻找Hibernate持久存在double
的类型。因此,您可以在DoubleType
中重构set(...)
方法。这意味着,在使用package-info中的Double
定义“myDouble”之后,您需要使用@org.hibernate.annotations.type(type="myDouble")
注释每个@org.hibernate.annotations.TypeDef
类型 - 我想您要避免所有这些维护(除此之外你必须进入Hibernate的核心)。
答案 1 :(得分:2)
您可以修改hibernate本身。您所要做的就是更改DoubleType类。
当然,你必须在hibernate发展时维护该补丁,但考虑到它在一个相当稳定的类中,这可能比为你的域模型中的每个double指定一个UserType更容易。
答案 2 :(得分:1)
Following this discussion,我感觉,hibernate没有提供将NaN转换为其他内容的方法。我认为,你必须提前阻止NaN值,甚至在它们被写入bean成员变量之前(比如将保护/转换代码添加到setter)。
修改强>
我担心,最好的不愉快的解决方案是使用保护代码,更糟糕的是,使用表格中的附加列来标记值是否为数字。什么肯定会使查询和插入操作复杂化。但是你需要在数据库中使用NaN并且你无法对抗jdbc驱动程序/数据库以正常运行(并接受NaN作为NUMBER字段的有效输入)。
答案 3 :(得分:1)
我最终使用了UserType解决方案,但通过单元测试解决了维护问题。类型类如下:
public class ParsedDoubleType extends DoubleType {
private static final long serialVersionUID = 1L;
@Override
public void set(PreparedStatement st, Object value, int index) throws SQLException {
Double doubleValue = (Double) value;
if (doubleValue.isInfinite() || doubleValue.isNaN()) {
Logger.getLogger(ParsedDoubleType.class).warn("Attempted to send a NaN or infinity value to the database "
+ "- this is not supported.\nStatement=" + st + " valueIndex=" + index);
doubleValue = Double.valueOf(0);
}
super.set(st, doubleValue, index);
}
}
单元测试大致是(为简洁起见,删除了一些细节):
Ejb3Configuration hibernateConfig = new Ejb3Configuration().configure("InMemoryDatabasePersistenceUnit", null);
for (Iterator<?> iterator = hibernateConfig.getClassMappings(); iterator.hasNext();) {
PersistentClass clazz = (PersistentClass) iterator.next();
Iterator<?> propertyIterator = clazz.getPropertyIterator();
while (propertyIterator.hasNext()) {
if (property.getType().equals(Hibernate.DOUBLE)) {
Assert.fail("Raw double type found. Annotate with @Type(type = \"package.ParsedDoubleType\")\n"
+ "Class " + clazz + " property " + property);
}
}
}
答案 4 :(得分:1)
我有完全相同的问题,并且在这些解决方案的指导下,我还准备了一个扩展DoubleType的自定义类型类。在该类中,我在set函数中将NaN值转换为null,反之亦然,因为对于我的数据库列,null是可以的。我还将NaN可能列的映射更改为自定义类型类。该解决方案非常适用于hibernate 3.3.2。
不幸的是,在将Hibernate升级到3.6.10后,它停止了工作。为了使它再次起作用,我将自定义类型替换为扩展DoubleType以实现UserType。
重要的数据类型函数实现应该如下:
private int[] types = { Types.DOUBLE };
public int[] sqlTypes()
{
return types;
}
@SuppressWarnings("rawtypes")
public Class returnedClass()
{
return Double.class;
}
以下是get和set函数:
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException
{
Double value = rs.getDouble(names[0]);
if (rs.wasNull())
return Double.NaN;
else
return value;
}
public void nullSafeSet(PreparedStatement ps, Object value, int index) throws HibernateException, SQLException
{
Double dbl = (Double) value;
if ((dbl == null) || (Double.isNaN(dbl)))
ps.setNull(index, Types.DOUBLE);
else
ps.setDouble(index, dbl);
}
答案 5 :(得分:-1)
@Column(name="doubleColumn"}
private Double doubleColumn = Double.NaN //yes, this is intentional. Verily.
public void setDouble(Double d)
{
if(d.isNan || d.isInfinite()
{
//do something nice here
}
else
this.doubleColumn = d;
}
public Double getDouble()
{
return !this.doubleColumn.isNaN() && !this.doubleColumn.isInfinite() ? this.doubleColumn : new Double();
}
....这很容易。