リレーショナルモデル
API (GraphQL) には、has one、has many、belongs to などのモデル間の関係を処理する機能があります。Amplify GraphQL API では、これは GraphQL データモデリングドキュメントで定義されている @hasOne、@hasMany、@belongsTo ディレクティブを使用して行われます。
デフォルトでは、GraphQL API リクエストは深さが 0 の選択セットを生成します。接続されたリレーショナルモデルは初期リクエストでは返されませんが、追加の API リクエストで必要に応じて遅延ロードできます。選択セットをカスタマイズするメカニズムを提供しており、これにより接続されたリレーションシップを初期リクエストで積極的にロードできます。
前提条件
次の例には、以下の最小バージョン要件があります。
- Amplify CLI v10.8.0
- Amplify Library for Swift v2.4.0
- このガイドは、Amplify CLI によって生成された更新されたモデルタイプを使用します。このガイドに従うには、
{project-directory}/amplify/cli.jsonで"generatemodelsforlazyloadandcustomselectionset"を見つけて、値をtrueに設定します。
モデル間のリレーショナリップを含む GraphQL スキーマを作成する
次の例では、スキーマに Post および Comment モデルを追加しましょう。
type Post @model { id: ID! title: String! rating: Int! comments: [Comment] @hasMany}
type Comment @model { id: ID! content: String post: Post @belongsTo}Amplify CLI を使用して、更新されたスキーマのモデルを生成します。
amplify codegen modelsリレーショナリップの作成
接続されたモデルを作成するには、接続するモデルのインスタンスを作成し、それを Amplify.API.mutate に渡します。
do { let post = Post(title: "My post with comments", rating: 10) let comment = Comment(content: "Loving Amplify API!", post: post) // Directly pass in the post instance let createPostResult = try await Amplify.API.mutate(request: .create(post)) guard case .success = createPostResult else { print("API response: \(createPostResult)") return } print("Post created.") let createCommentResult = try await Amplify.API.mutate(request: .create(comment)) guard case .success = createCommentResult else { print("API response: \(createCommentResult)") return } print("Comment created.")} catch { print("Create post or comment failed", error)}リレーショナリップのクエリ
次の例は、Post の初期ロード、その後の Post のコメントのページを読み込むための取得を示しています。
do { let queryPostResult = try await Amplify.API.query(request: .get(Post.self, byIdentifier: "123")) guard case .success(let queriedPostOptional) = queryPostResult, let queriedPost = queriedPostOptional, let comments = queriedPost.comments else { print("API response: \(queryPostResult)") return } try await comments.fetch() print("Fetched \(comments.count) comments")} catch { print("Failed to query post or fetch comments", error)}コメントを読み込むか取得するには、常に fetch() を呼び出してください。コメントがクエリの一部としてロードされた場合は、すぐに返されます。接続されたリレーショナリップを積極的にロードする方法については、カスタム選択セットを使用したクエリの深さのカスタマイズを参照してください。
リレーショナリップの削除
1 対多のリレーショナリップで親オブジェクトを削除すると、子は削除されません。孤立したデータを防ぐために、親を削除する前に子を削除します。
do { let deleteCommentResult = try await Amplify.API.mutate(request: .delete(comment)) guard case .success = deleteCommentResult else { print("API response: \(deleteCommentResult)") return } // Once all comments for a post are deleted, the post can be deleted. let deletePostResult = try await Amplify.API.mutate(request: .delete(post)) guard case .success = deletePostResult else { print("API response: \(deletePostResult)") return } print("Deleted comment and post")} catch { print("Failed to delete comment or post", error)}多対多のリレーショナリップ
多対多のリレーショナリップの場合、@manyToMany ディレクティブを使用して relationName を指定できます。内部的には、Amplify はジョインテーブルと両方のモデルからの 1 対多のリレーショナリップを作成します。
type Post @model { id: ID! title: String! rating: Int editors: [User] @manyToMany(relationName: "PostEditor")}
type User @model { id: ID! username: String! posts: [Post] @manyToMany(relationName: "PostEditor")}do { let post = Post(title: "My Post", rating: 10) let user = User(username: "User") let postEditor = PostEditor(post: post, user: user) let createPostResult = try await Amplify.API.mutate(request: .create(post)) guard case .success = createPostResult else { print("API response: \(createPostResult)") return } let createUserResult = try await Amplify.API.mutate(request: .create(user)) guard case .success = createUserResult else { print("API response: \(createUserResult)") return } let createPostEditorResult = try await Amplify.API.mutate(request: .create(postEditor)) guard case .success = createPostEditorResult else { print("API response: \(createPostEditorResult)") return }} catch { print("Failed to create post, user, or post editor", error)}カスタム選択セットを使用したクエリの深さのカスタマイズ
GraphQL リクエストのオプション includes パラメータを指定することで、ネットワークリクエストを介して接続されたモデルをネストされたクエリで実行できます。
Comment とそれが属する Post をクエリします。
do { let queryCommentResult = try await Amplify.API.query(request: .get(Comment.self, byIdentifier: "c1", includes: { comment in [comment.post] })) guard case .success(let queriedCommentOptional) = queryCommentResult, let queriedComment = queriedCommentOptional, let loadedPost = try await queriedComment.post else { print("API response: \(queryCommentResult)") return } print("Post: ", loadedPost)} catch { print("Failed to query comment with post", error)}これにより、GraphQL ドキュメントのポストの選択セットが入力されます。これはGraphQL サービスに操作の一部としてポストモデルを取得することを示します。コメントが読み込まれると、ポストモデルはすぐにメモリで利用可能になり、追加のネットワークリクエストは不要です。
Post と Post のコメントの最初のページをクエリします。
do { let queryPostResult = try await Amplify.API.query(request: .get(Post.self, byIdentifier: "p1", includes: { post in [post.comments] })) guard case .success(let queriedPostOptional) = queryPostResult, let queriedPost = queriedPostOptional, let comments = queriedPost.comments else { print("API response: \(queryPostResult)") return } try await comments.fetch() print("Comments: ", comments)} catch { print("Failed to query post with comments", error)}Post のネットワークリクエストにコメントが含まれます。1 つのネットワーク呼び出しでコメントの最初のページを積極的にロードします。
includes パラメータを通じて複雑なネストされたクエリを生成できます。
let queryCommentResult = try await Amplify.API.query(request: .get(Comment.self, byIdentifier: "p1", includes: { comment in [comment.post.comments]}))このクエリは、コメントを取得し、親ポストおよび Post のコメントの最初のページを積極的にロードします。
let queryCommentResult = try await Amplify.API.query(request: .get(PostEditor.self, byIdentifier: "pe1", includes: { postEditor in [postEditor.post, postEditor.user]}))このクエリは、postEditor を取得し、その post と user を積極的にロードします。