3

プログレスデータベースに接続するJPAプロバイダーとしてHibernateを使用しています。NaN 値が永続化されると、多くの問題が発生します。これにより、特定の状況で行が読み取られなくなります。NaN (およびおそらく + および - 無限大) を別の値に変換するために、標準的な double 型の永続性にフックする方法はありますか? NaN や無限大の情報が失われても構いません。読み取り可能な行が欲しいだけです。

私はこのようなことができることを知っています:

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

しかし、データベースにマップされた double に対して手動で追加する必要があるため、メンテナンスについて心配しています。

4

6 に答える 6

3

これに対する私の第一印象は、Hibernate が存続するタイプを探すことですdoubleset(...)したがって、 でメソッドをリファクタリングできますDoubleType。これは、package-info で「myDouble」を使用して定義した後に、すべてDoubleの型に注釈を付ける必要があることを意味します。メンテナンスのためにこれをすべて回避したいと思います (それを超えて、Hibernate の中心部に入る必要があります)。 )。@org.hibernate.annotations.type(type="myDouble")@org.hibernate.annotations.TypeDef

于 2009-11-28T00:30:37.047 に答える
2

休止状態自体を変更できます。クラス DoubleType を変更するだけです。

もちろん、休止状態が進化するにつれてそのパッチを維持する必要がありますが、それが単一のかなり安定したクラスにあることを考えると、ドメイン モデルのすべての double に対して 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 に答える
2

この議論に続いて、休止状態は NaN を別のものに変換する方法を提供しないと感じています。NaN 値が Bean メンバー変数に書き込まれる前であっても (セッターにガード/変換コードを追加するなど)、早期に NaN 値を防止する必要があると思います。

編集

残念ながら、最善の不快な解決策は、ガード コードを使用することです。さらに悪いことに、テーブルに追加の列を使用して、値が数値であるかどうかに関係なくフラグを立てます。確かに、クエリと挿入操作が複雑になります。ただし、データベースに NaN が必要であり、jdbc ドライバー/データベースが適切に動作するように戦うことはできません (また、NaN を NUMBER フィールドの有効な入力として受け入れることもできません)。

于 2009-11-27T09:54:33.700 に答える
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の永続性を理解するのに問題があります。データベース エンティティは、ゲッターとセッターを介して自己管理されます。これらは、必要な検証を行うことができます。それらを使用せずに属性を実際に設定すると、オブジェクト指向開発と永続化の中核となる概念、特にマネージド エンティティが失われます。プロジェクトを再設計する必要があると思います。これらの問題は、基本的な設計上の欠陥の確かな兆候です...ここでいくつかのアドバイスを与えるだけです-そしてそれが解決策です:

@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 に答える