最新の安定バージョンについては、Spring Data Neo4j 8.0.1 を使用してください! |
Spring Data オブジェクトマッピングの基礎
このセクションでは、Spring Data オブジェクトのマッピング、オブジェクトの作成、フィールドとプロパティのアクセス、可変性と不変性の基本について説明します。
Spring Data オブジェクトマッピングの中心的なロールは、ドメインオブジェクトのインスタンスを作成し、ストアネイティブデータ構造をそれらにマッピングすることです。つまり、2 つの基本的な手順が必要です。
公開されたコンストラクターの 1 つを使用したインスタンスの作成。
すべての公開されたプロパティを具体化するインスタンスの設定。
オブジェクト作成
Spring Data は、その型のオブジェクトの具体化に使用される永続エンティティのコンストラクターを自動的に検出しようとします。解決アルゴリズムは次のように機能します。
引数のないコンストラクターがある場合は、それが使用されます。他のコンストラクターは無視されます。
引数を取る単一のコンストラクターがある場合は、それが使用されます。
引数を取る複数のコンストラクターがある場合、Spring Data が使用するコンストラクターに
@PersistenceCreatorのアノテーションを付ける必要があります。
値の解決は、コンストラクターの引数名がエンティティのプロパティ名と一致することを前提としています。つまり、マッピングのすべてのカスタマイズ(異なるデータストア列またはフィールド名など)を含む、プロパティが設定されるかのように解決が実行されます。また、これには、クラスファイルで使用可能なパラメーター名情報、またはコンストラクターに存在する @ConstructorProperties アノテーションのいずれかが必要です。
プロパティ設定
エンティティのインスタンスが作成されると、Spring Data はそのクラスの残りのすべての永続プロパティを設定します。エンティティのコンストラクターによってすでに入力されていない場合(つまり、コンストラクターの引数リストを介して使用される場合)、ID プロパティが最初に入力され、循環オブジェクト参照の解決が可能になります。その後、コンストラクターによってまだ設定されていないすべての非一時的なプロパティがエンティティインスタンスに設定されます。そのために、次のアルゴリズムを使用します。
プロパティが不変であってもウィザーメソッド (以下を参照) を公開する場合、ウィザーを使用して新しいプロパティ値を持つ新しいエンティティインスタンスを作成します。
プロパティアクセス (つまり、getter および setter を介したアクセス) が定義されている場合は、setter メソッドを呼び出します。
デフォルトでは、フィールド値を直接設定します。
次のエンティティを見てみましょう。
class Person {
private final @Id Long id; (1)
private final String firstname, lastname; (2)
private final LocalDate birthday;
private final int age; (3)
private String comment; (4)
private @AccessType(Type.PROPERTY) String remarks; (5)
static Person of(String firstname, String lastname, LocalDate birthday) { (6)
return new Person(null, firstname, lastname, birthday,
Period.between(birthday, LocalDate.now()).getYears());
}
Person(Long id, String firstname, String lastname, LocalDate birthday, int age) { (6)
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
this.birthday = birthday;
this.age = age;
}
Person withId(Long id) { (1)
return new Person(id, this.firstname, this.lastname, this.birthday);
}
void setRemarks(String remarks) { (5)
this.remarks = remarks;
}
}| 1 | identifier プロパティは final ですが、コンストラクターで null に設定されます。クラスは、識別子の設定に使用される withId(…) メソッドを公開します。インスタンスがデータストアに挿入され、識別子が生成されたとき。元の Vertex インスタンスは、新しいインスタンスが作成されるときに変更されません。通常、ストア管理される他のプロパティにも同じパターンが適用されますが、永続化操作のために変更する必要がある場合があります。 |
| 2 | firstname および lastname プロパティは、getter を介して潜在的に公開される通常の不変のプロパティです。 |
| 3 | age プロパティは不変ですが、birthday プロパティから派生しています。示されている設計では、Spring Data は宣言された唯一のコンストラクターを使用するため、データベース値はデフォルト設定よりも優先されます。計算が優先されることを意図している場合でも、このコンストラクターがパラメーターとして age をとることが重要です(それを無視する可能性がある)。そうしないと、プロパティ生成ステップは年齢フィールドを設定しようとし、不変であり、枯れています。 |
| 4 | comment プロパティは可変であり、フィールドを直接設定することで入力されます。 |
| 5 | remarks プロパティは可変であり、comment フィールドを直接設定するか、setter メソッドを呼び出して設定します。 |
| 6 | このクラスは、オブジェクト作成用のファクトリメソッドとコンストラクターを公開します。ここでの核となる考え方は、追加のコンストラクターの代わりにファクトリメソッドを使用して、@PersistenceCreator によるコンストラクターの明確化の必要性を回避することです。代わりに、プロパティのデフォルト設定はファクトリメソッド内で処理されます。 |
一般的な推奨事項
不変オブジェクトに固執するようにしてください — 不変オブジェクトは、オブジェクトを実体化するためにコンストラクターを呼び出すだけなので、簡単に作成できます。また、これにより、クライアントコードによるオブジェクトの状態の操作を可能にする setter メソッドがドメインオブジェクトに散在するのを防ぎます。これらが必要な場合は、同じ場所にある限られた種類の型によってのみ呼び出せるように、パッケージで保護することをお勧めします。コンストラクターのみの具体化は、プロパティの作成より最大 30% 高速です。
all-args コンストラクターを提供する — エンティティを不変の値としてモデル化できない、またはしたくない場合でも、オブジェクトのマッピングがプロパティの設定をスキップできるため、エンティティのすべてのプロパティを引数として取るコンストラクターを提供することには価値があります。最適なパフォーマンスのため。
@PersistenceCreatorを回避するために、オーバーロードされたコンストラクターの代わりにファクトリメソッドを使用します — 最適なパフォーマンスに必要なすべての引数コンストラクターでは、通常、自動生成識別子などを省略したアプリケーションユースケース固有のコンストラクターを公開します。これらの all-args コンストラクターのバリアントを公開する静的ファクトリメソッド。生成されたインスタンシエーターおよびプロパティアクセサークラスの使用を許可する制約を必ず遵守してください。
識別子を生成するには、final フィールドを wither メソッドと組み合わせて使用します。
Lombok を使用してボイラープレートコードを回避します — 永続化操作は通常、すべての引数を取るコンストラクターを必要とするため、その宣言はフィールド割り当てに対するボイラープレートパラメーターの退屈な繰り返しとなりますが、Lombok の
@AllArgsConstructorを使用することで回避することができます。
不変マッピングに関する注意事項
可能な限り不変のマッピングと構成を使用することをお勧めしますが、マッピングに関してはいくつかの制限があります。A に B へのコンストラクター参照があり、B に A への参照があるという双方向の関連、またはより複雑なシナリオが考えられます。この鶏が先か卵が先かという状況は、Spring Data Neo4j では解決できません。A のインスタンス化中に、完全にインスタンス化された B が必要になりますが、その一方で、A のインスタンス (正確には同じインスタンス) が必要です。SDN では一般にこのようなモデルが許可されていますが、データベースから返されたデータに上記のようなコンスタレーションが含まれている場合は、実行時に MappingException がスローされます。返されるデータがどのようなものであるかを予測できないようなケースやシナリオでは、リレーションシップの可変フィールドの方が適しています。
Kotlin サポート
Spring Data は、Kotlin の仕様を適合させて、オブジェクトの作成と変更を可能にします。
Kotlin オブジェクトの作成
Kotlin クラスはインスタンス化がサポートされており、すべてのクラスはデフォルトで不変であり、可変プロパティを定義するには明示的なプロパティ宣言が必要です。次の data クラス Vertex を検討してください。
data class Person(val id: String, val name: String) 上記のクラスは、明示的なコンストラクターを持つ典型的なクラスにコンパイルされます。別のコンストラクターを追加してこのクラスをカスタマイズし、@PersistenceCreator でアノテーションを付けてコンストラクターの設定を示します。
data class Person(var id: String, val name: String) {
@PersistenceCreator
constructor(id: String) : this(id, "unknown")
}Kotlin は、パラメーターが提供されない場合にデフォルト値を使用できるようにすることで、パラメーターのオプションをサポートしています。Spring Data がパラメーターのデフォルト設定を持つコンストラクターを検出した場合、データストアが値を提供しない(または単に null を返す)場合、Kotlin はパラメーターのデフォルト設定を適用できるため、これらのパラメーターは存在しません。name のパラメーターのデフォルト設定を適用する次のクラスを検討してください。
data class Person(var id: String, val name: String = "unknown")name パラメーターが結果の一部ではないか、その値が null であるたびに、name は unknown にデフォルト設定されます。