3

我使用 Hibernate 作为我的 JPA 提供程序,它连接到 Progress 数据库。当 NaN 值持续存在时,它会导致很多问题 - 它会阻止在某些情况下读取该行。有没有办法连接到标准的双类型持久性以将 NaN(可能还有 + 和 - 无穷大)转换为不同的值?NaN 或无穷大信息是否丢失都没关系,我只想要一个可读的行!

我知道我可以做这样的事情:

@Column(name = "doubleColumn")
public double getDoubleColumn() {
    return PersistedDouble.convert(doubleColumn);
}

但我担心维护,因为必须为映射到数据库的任何双打手动添加。

4

6 回答 6

3

我对此的第一印象是寻找 Hibernate 坚持的类型double。所以你可以重构set(...). 这意味着尽管在使用 package-info 定义“myDouble”之后DoubleType,您需要注释每种Double类型——我认为您希望避免所有这些以进行维护(除此之外,您还必须进入 Hibernate 的核心)。@org.hibernate.annotations.type(type="myDouble")@org.hibernate.annotations.TypeDef

于 2009-11-28T00:30:37.047 回答
2

在这个讨论之后,我有一种感觉,hibernate 没有提供将 NaN 转换为其他东西的方法。我认为,您必须更早地阻止 NaN 值,甚至在将它们写入 bean 成员变量之前(例如向设置器添加保护/转换代码)。

编辑

我担心,最好的不愉快的解决方案是使用保护代码,更糟糕的是,在表格上增加一列来标记值是否为数字。什么肯定会使查询和插入操作复杂化。但是您需要数据库中的 NaN,并且您无法与 jdbc 驱动程序/数据库对抗以使其正常运行(并接受 NaN 作为 NUMBER 字段的有效输入)。

于 2009-11-27T09:54:33.700 回答
2

你可以修改hibernate本身。您所要做的就是更改 DoubleType 类。

当然,随着 hibernate 的发展,您必须维护该补丁,但考虑到它在一个单一的、相当稳定的类中,这可能比为域模型中的每个双精度指定一个 UserType 更容易。

于 2009-11-28T00:51:02.793 回答
2

我最终使用了 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);
        }
    }
}
于 2009-11-28T11:31:21.790 回答
1

我遇到了完全相同的问题,在这些解决方案的指导下,我还准备了一个自定义类型类扩展 DoubleType。在该类中,我在 set 函数中将 NaN 值转换为 null,对于 get 函数反之亦然,因为 null 对于我的数据库列是可以的。我还将 NaN 可能列的映射更改为自定义类型类。该解决方案非常适合休眠 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);
}
于 2013-03-05T14:52:29.960 回答
-1

抱歉,但从您的示例和问题来看,您实际上在理解 Java 持久性方面存在问题。数据库实体通过 getter 和 setter 进行自我管理——它们可以进行您希望它们进行的任何验证。如果您真的在没有它们的情况下设置属性,那么您将缺少面向对象开发和持久性的核心概念——尤其是托管实体。我认为你需要重新设计你的项目,遇到这样的问题是基本设计缺陷的明确标志......在这里给出一些建议 - 这就是解决方案:

@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();
}

....就这么简单。

于 2013-06-21T05:33:03.227 回答