さまざまな状況でさまざまなHibernateユーザータイプを使用する
-
06-07-2019 - |
質問
Hibernate + JPAをORMソリューションとして使用しています。
ユニットテストにHSQLを使用し、実際のデータベースとしてPostgreSQLを使用しています。
Postgresのネイティブ UUID Hibernateで入力し、ユニットテスト用にHSQLで文字列表現のUUIDを使用します(HSQLにはUUIDタイプがないため)。
PostgresとHSQLの単体テストに異なる構成の永続性XMLを使用しています。
Hibernateを使用する方法を次に示します" see&quot ;;私のカスタムUserType:
@Id
@Column(name="UUID", length=36)
@org.hibernate.annotations.Type(type="com.xxx.UUIDStringType")
public UUID getUUID() {
return uuid;
}
public void setUUID(UUID uuid) {
this.uuid = uuid;
}
それはうまく機能します。ただし、必要なのは、「com.xxx.UUIDStringType」をスワップアウトする機能です。 XMLまたはプロパティファイルからのアノテーションの一部で、再コンパイルせずに変更できます。
アイデアはありますか
解決
この質問は本当に古く、長い間答えられてきましたが、最近、私はこの同じ状況にあり、良い解決策を見つけました。まず最初に、Hibernateには3つの異なる組み込みUUIDタイプの実装があることがわかりました。
-
binary-uuid
:UUIDをバイナリとして保存します -
uuid-char
:UUIDを文字シーケンスとして保存します -
pg-uuid
:ネイティブのPostgres UUIDタイプを使用します
これらのタイプはデフォルトで登録されており、特定のフィールドに @Type
アノテーションで指定できます。例:
@Column
@Type(type = "pg-uuid")
private UUID myUuidField;
Dialect
のデフォルトタイプをオーバーライドするメカニズムも あります。したがって、最終展開がPostgresデータベースと通信するが、ユニットテストでHSQLを使用する場合、 pg-uuid
タイプをオーバーライドして、次のようなカスタム方言を作成することにより、文字データを読み書きできます:
public class CustomHSQLDialect extends HSQLDialect {
public CustomHSQLDialect() {
super();
// overrides the default implementation of "pg-uuid" to replace it
// with varchar-based storage.
addTypeOverride(new UUIDCharType() {
@Override
public String getName() {
return "pg-uuid";
}
});
}
}
カスタムダイアレクトをプラグインするだけで、両方の環境で pg-uuid
タイプが使用可能になります。
他のヒント
やあ、Hibernate 4で解決策を探している人(Dialect#addTypeOverrideメソッドはもう利用できないため)のために、このSteve Ebersoleのコメント
次のようなカスタムユーザータイプを作成する必要があります。
public class UUIDStringCustomType extends AbstractSingleColumnStandardBasicType {
public UUIDStringCustomType() {
super(VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE);
}
@Override
public String getName() {
return "pg-uuid";
}
}
HSQLDBダイアレクトにバインドするには、次のようにDialect#contributeTypesメソッドをオーバーライドするカスタムダイアレクトを構築する必要があります。
public class CustomHsqlDialect extends HSQLDialect {
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes(typeContributions,serviceRegistry);
typeContributions.contributeType(new UUIDStringCustomType());
}
}
その後、2つのデータベースで@Type(type =" pg-uuid")を使用できます。
誰かに役立つことを願っています...
@Type
アノテーションを指定せずにUUIDタイプ間の問題を回避するには)そのパッケージのhibernates @TypeDef
アノテーションで package-info.java
を使用しています。
アプリケーションのセットアップ例は次のとおりです。
module / src / main / java / app.package.domain
にエンティティが含まれていると仮定します。そして、あなたのテストは module / src / test / java / app.package
に保存されます。
domain
パッケージに2つの package-info.java
を作成するだけです。
package-infoファイルが常に同じパッケージにあることを確認します(テスト用と本番用)。以下の例を参照してください。
src/main/java
app
package
domain
package-info.java
src/test/java
app
package
domain
package-info.java
プロダクション package-info.java
のコンテンツは次のようになります(Postgres):
@TypeDef(
name = "pg-uuid",
defaultForType = UUID.class,
typeClass = PostgresUUIDType.class
)
package app.package.domain;
import org.hibernate.annotations.TypeDef;
import org.hibernate.type.PostgresUUIDType;
import java.util.UUID;
これは、「構成」をテストする方法です。 (H2)のようになります:
@TypeDef(
name = "uuid-char",
defaultForType = UUID.class,
typeClass = UUIDCharType.class
)
package app.package.domain;
import org.hibernate.annotations.TypeDef;
import org.hibernate.type.UUIDCharType;
import java.util.UUID;
希望する
データベースの機能に応じて正しいことを行うために、ユーザータイプにスマートを構築することができます。 Hibernate自体も、「ネイティブ」で同様のアプローチを取ります。 IDジェネレータ。使用しているデータベースのタイプに応じて動作が異なります。このようなアプローチにより、実行時にマッピングを切り替える必要がなくなります。
たとえば、データベースごとに1つの戦略クラスを作成できます。次に、ユーザータイプクラスで、最初に呼び出されたときに接続しているデータベースを検出し、そのデータベースの適切な戦略をインスタンス化してから、すべての呼び出しを戦略オブジェクトに委任します。