11

次のようなJPA注釈付きタイプを使用しています(Groovyコード)。

@Entity
@EqualsAndHashCode
class TextNote extends Serializable {
    @Id Long id
    String text
}

それが最初に書かれたとき、私はJPAに非常に慣れておらず、最初にSQLを書き、次に注釈付きクラスをSQLと一致させました。PostgreSQLを読んでみると、私が欲しかったテーブルは次のようでした。

CREATE TABLE textnote (
    id bigint NOT NULL,
    text text
);

これは機能し、次のようなテーブルがありました。

 id  |          text
-----+------------------------
 837 | really long text here

私が今やりたいのは、JPAエンティティを次のように修正することです。

@Entity
@EqualsAndHashCode
class TextNote extends Serializable {
    @Id Long id
    @Lob String text
}

アノテーションを追加すること@Lobで、データベースを交換したい場合に備えて、JPAプロバイダー(私の場合は休止状態)がDDLを正しく生成できます。また、テキストフィールドを正確に文書化します。メモが作成されると、次のように表示されます。

 id  |          text
-----+------------------------
 837 | 33427

String getText()を使用してコードで読み取ると、非常に長いテキストが返されるため、これは新しいメモには問題ありません。正直なところ、PostgreSQLがこの型をどのように実装しているかはわかりませんtextし、理論的にもそうする必要はありません。ただし、本番データベースには、@Lob注釈なしの古いコードを使用して保存された多くのメモがすでにあります。既存のデータベースで新しいコードを実行すると、次のような問題が発生します。

org.springframework.dao.DataIntegrityViolationException: Bad value for type long : not a number this time; SQL [n/a]; nested exception is org.hibernate.exception.DataException: Bad value for type long : not a number this time

既存のメモの場合、SQLで古いメモを移行して、正しく使用@Lobおよび入力する方法はありますか?text前もって感謝します。

4

4 に答える 4

13

Postgresのラージオブジェクトのドキュメントに基づくと、各テキストチャンクをファイルに書き込んで個別にインポートする必要があるようです。これは、SQLで行うべきことではありません。

JPAについては何も知りませんが@Lob、DDLまたはデータベースの切り替えとは何の関係がありますか?列のタイプを完全に変更しました。textPostgresのタイプの何が問題になっていますか?


コメントで失われないように、ここでループを閉じます。

本当の問題はPostgres列を@Lob作成することでしたが、 HibernateはそれをネイティブのPostgres「ラージオブジェクト」として扱い、データを他の場所に保存し、テーブルにoidのみを残します(列タイプに従ってテキストとして保存されていました)。これは通常、テキストに必要なものではありません。text

OPの解決策は、平手打ちし@Type(type="org.hibernate.type.StringClobType")てHibernateに通常のテキストを保存させることでした。

Postgresは通常、テキストを5桁の整数として保存しません。:)

于 2013-01-25T00:10:32.213 に答える
8

私はJPAを使用してエンティティに注釈を付け、休止状態にして永続化します。ただし、エンティティに休止状態の特定の注釈を追加したくありません。したがって、エンティティと注釈を含むデータjarがあります。次に、私の実装では、persistence.xmlを指定し、「CustomTypes.hbm.xml」を追加します。これは自動スキャンされるか、persistence.xmlのmapping-fileタグを介して追加されます。

このマッピングには、basictyperegistryからオーバーライドするタイプが含まれています。この場合、materialized_clobタイプが使用されます。クエリツールを使用してデータベースを参照するときに、実際のコンテンツを直接表示できるようにしたいので、これは望ましくありません。だから私は追加します:

<typedef name="materialized_clob" class="org.hibernate.type.TextType" />

データパッケージに特定の注釈を追加することなく、すべてのClobに指定されたタイプを強制的に使用するため。

DEBUGレベルでorg.hibernate.type.BasicTypeRegistryをログに記録することで、マッピングを確認できます。

これを理解するのに少し時間がかかりました。これが同じ問題に直面している人の助けになることを願っています。これはおそらくあなたの問題も解決するので、ここに投稿する価値があるかもしれないと思いました。

于 2013-06-25T12:19:13.887 に答える
2

遅いと思いますが、将来同じ問題を抱えている人にとっては。

また、OIDとしてではなく、テキストの列に直接古いデータが含まれているという同様の問題に直面しました。そして、アップグレードされたアプリケーションでそのデータを使用しようとしたとき、私も取得していました

Bad value for type long

これを解決するために、このスクリプトを作成しました。将来誰かを助けることができるかもしれません。

私はここでこの投稿から大きな助けを得ました

于 2015-04-07T05:22:27.493 に答える
0

スプリングを使用している場合は、LocalSessionFactoryBean子孫を作成してHibernateタイプのオーバーライドを注入できます。例を参照してください:

 public class CustomSessionFactoryBean extends LocalSessionFactoryBean {

    @Override
    protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
        // To store @Lob annotated Strings in TEXT fields.
        // By default for Postgres generated TEXT column, but stored OID of Postgres LOB object
        sfb.registerTypeOverride(new TextType() {
            @Override
            public String getName() {
                return StandardBasicTypes.MATERIALIZED_CLOB.getName();
            }
        });
        sfb.registerTypeOverride(new NTextType() {
            @Override
            public String getName() {
                return StandardBasicTypes.MATERIALIZED_NCLOB.getName();
            }
        });

        super.buildSessionFactory(sfb);
    }
 }

Hibernate固有のアノテーションを使用する必要はありません。String@Typeプロパティにアノテーションを付けて使用するだけです@LobCustomSessionFactoryBean

于 2014-09-30T11:19:06.583 に答える