エンティティ内のオブジェクト
リレーショナルデータモデルがあるとします。 一部のエンティティについては、何らかのオブジェクト(必要に応じてドキュメント)を保存する必要がある場合があります。 もちろん、1つ(または複数の)エンティティを使用してこのオブジェクトのデータモデルを拡張することも、単にこのオブジェクトをバイトの配列として格納することもできます。 しかし、PostgreSQLには、 RFC 4627に従ってjsonオブジェクトを格納できるjsonデータ型が長い間ありました。 それがどのように使用され、どのような機会を与えることができるかが興味深いものになりました。 私が最初にグーグルに行ったとき、私はいくつかの非構造化された投稿と何かを説明するQ&Aを見つけましたが、完全な絵を与えませんでした。 少し調べて、何が何であるかを理解したので、これらのフィールドの使用は非常に便利であるという結論に達し、json型の使用を簡素化する小さなライブラリを作成することにしました。 以下では、その使用方法を説明し、最初に思い浮かぶ代替案ともう少し比較します。
方言
もちろん、標準の方言でこのタイプがサポートされていることには疑問の余地はありません。 hibernateが型自体を認識し、スキームを検証/更新することを本当に望んでいます。 したがって、ライブラリにはPostgreSQL9Dialectを拡張するJsonPostgreSQLDialect方言が含まれています。 persistance.xmlでこの方言を使用するだけです。
保存するオブジェクト
jsonフィールドにオブジェクトとMapの両方を保存できます。 オブジェクトを保存する場合は、PGJsonObjectを保存するクラスを継承します
public class CacheObject extends PGJsonObject { ... }
エンティティで注釈タイプ定義を作成します。
@Entity @TypeDefs({@TypeDef( name= "JsonObject", typeClass = CacheObject.class)}) public class Product { ... @Type(type = "JsonObject") public CacheObject getCache() { return cache; } }
これにより継承スキームが破られた場合、そのタイプのクラスとは別のクラスを作成できます。 同じPGJsonObjectを継承し、returnedClass()メソッドをオーバーライドする必要があります。このメソッドでは、格納するオブジェクトのクラスを返します。 次に、このクラスをエンティティで使用してタイプを決定する必要があります。
public class JsonCustomType extends PGJsonObject { @Override public Class returnedClass() { return Custom.class; } }
エンティティのタイプ定義は次のようになります。
@Entity @TypeDefs({@TypeDef( name= "JsonObject", typeClass = JsonCustomType.class)}) public class Product { ... @Type(type = "JsonObject") public Custom getCustom() { return custom; } }
Mapを保存する場合は、既にライブラリにあるJsonMapTypeタイプを使用します。
推奨事項
- オブジェクトデータの変更には注意してください。 格納しているオブジェクトが不変でない場合、オブジェクトで行った変更はすべてデータベースに保存されます(もちろん、トランザクションがロールバックされない場合)。したがって、変更を保存しない場合はコピーを作成します。
- ネイティブクエリを確認してください。 エンティティがリストされていることを確認してください。
JSONフィールドの利点
2つの代替実装がすぐに思い浮かぶ
- オブジェクトのデータベーススキーマを拡張する
- バイト配列を保存する
最初のオプションは、オブジェクトに深い階層がある場合、データモデルを大幅に複雑化する可能性があります。 オブジェクトにポイントの配列などの大きな配列が格納されている場合、ポイントのあるテーブルには膨大な数のレコードが含まれ、選択が遅くなる可能性があります。 また、このオプションでは、アプリケーションはテーブルからデータスキームを引き出すために、データスキームに関するすべての情報を知っている必要があります。
2番目のオプションでは、スキームを展開する必要はありませんが、このフィールドに格納されている情報は絶対に代表的ではなく、インデックス化できません。 また、前のケースと同様に、アプリケーションは保存されたデータの構造を知っている必要がありますが、今回は適切な逆シリアル化のためだけです。
jsonフィールドを使用すると、データベース内のすべての情報が読みやすい形式で表示されます。 また、PostgreSQLのjson関数のおかげで、jsonオブジェクトの特定のフィールドを選択するための便利なネイティブクエリを作成できます。 また、 式のインデックスのおかげで、jsonオブジェクトの任意のフィールドにインデックスを掛けることができます。
また、jsonフィールドを使用すると、統合タスクで非常に役立ちます。 jsonフィールドの1つの場所にオブジェクトを保存し、別の場所にオブジェクトを保存すると、そのフィールドからマップを取得できます。 オブジェクトの構造の一部しかわからない場合、jsonオブジェクトの既知の必要な部分のみをJavaオブジェクトにデシリアライズし、残りを無視するか、Mapで再度デシリアライズできます。
プロジェクトのソースコードはgithubにあります。 これまでのところ、プロジェクトは粗雑です。 将来的には使用を簡素化し、注釈を導入したいと考えています。