Name:
interface
Value:
Amplify has re-imagined the way frontend developers build fullstack applications. Develop and deploy without the hassle.

Page updated Jul 2, 2024

Maintenance ModeYou are viewing Amplify Gen 1 documentation. Amplify Gen 1 has entered maintenance mode and will reach end of life on May 1, 2027. New project should use Amplify Gen 2. For existing Gen 1 projects, a migration guide and tooling are available to help you upgrade. Switch to the latest Gen 2 docs →

リレーショナルモデル

API (GraphQL) には、has onehas manybelongs to などのモデル間の関係を処理する機能があります。Amplify GraphQL API では、これは GraphQL データモデリングドキュメントで定義されている @hasOne@hasMany@belongsTo ディレクティブを使用して行われます。

デフォルトでは、GraphQL API リクエストは深さが 0 の選択セットを生成します。接続されたリレーショナルモデルは初期リクエストでは返されませんが、追加の API リクエストで必要に応じて遅延ロードできます。選択セットをカスタマイズするメカニズムを提供しており、これにより接続されたリレーションシップを初期リクエストで積極的にロードできます。

Amplify CLI @aws-amplify/cli@12.12.2 および API Category @aws-amplify/amplify-category-api@5.11.5 のバージョンでは、スキーマ内の関連モデルに異なる認可ルールが適用される場合のサブスクリプションでのリレーショナルフィールドデータの処理方法が改善されました。この改善により、リレーショナルフィールドの値が編集され、不正アクセスを防ぐために null または空として表示されます。

この編集は、子モデルが親モデルと同じアクセス許可で保護されることを確認できない場合に発生します。

サブスクリプションはミューテーションに関連付けられており、ミューテーション結果で提供される選択セットはサブスクリプションに渡されるため、ミューテーション結果のリレーショナルフィールドは編集される必要があります。

認可されたエンドユーザーが編集されたリレーショナルフィールドにアクセスする必要がある場合は、クエリを実行してリレーショナルデータを読み取る必要があります。

また、リレーショナルフィールドが必須として設定されている場合、サブスクリプションは関連する認可を継承します。リレーショナルデータをより適切に保護するために、スキーマを修正してオプションのリレーショナルフィールドを使用することを検討してください。

  • 遅延ロードと積極的ロード: ミューテーションとサブスクリプションでは、リレーションシップの遅延ロードと積極的ロードはサポートされなくなりました。ただし、クエリの遅延ロードと積極的ロードは引き続き実行できます。

  • サブスクリプションと関連モデル: サブスクリプションを実行して関連モデルを取得する必要がある場合は、サブスクリプションイベントからモデル識別子を使用して遅延ロードまたは積極的ロードされたクエリを実行して、関連データを取得してください。

アプリケーションのセキュリティ状況に基づいて、この改善が加えられる前のサブスクリプション動作に戻すことを選択できます。 そうするには、amplify/backend/cli.json ファイルの graphqltransformer 下の subscriptionsInheritPrimaryAuth 機能フラグを使用します。

  • 有効な場合、サブスクリプションはリレーショナルフィールドのプライマリモデル認可ルールを継承します。
  • 無効な場合、プライマリモデルと関連モデル間の認可ルールに違いがある場合、ミューテーション応答のリレーショナルフィールドは編集されます。

前提条件

次の例には、以下の最小バージョン要件があります。

  • Amplify CLI v10.8.0
  • Amplify Library for Swift v2.4.0
  • このガイドは、Amplify CLI によって生成された更新されたモデルタイプを使用します。このガイドに従うには、{project-directory}/amplify/cli.json"generatemodelsforlazyloadandcustomselectionset" を見つけて、値を true に設定します。

プロジェクトに既存のリレーショナルモデルがある場合は、機能フラグを更新した後、amplify codegen models を再実行する必要があります。モデルが更新されたら、一部のリレーションシップが async に変更されたため、破棄的変更に対処する必要があります。このページの残りのガイドに従って、新しい遅延ロードサポートモデルの使用方法について詳しく学びます。

モデル間のリレーショナリップを含む 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 対多のリレーショナリップを作成します。

ジョインテーブルレコードは、関連するレコードを削除する前に削除する必要があります。たとえば、PostTag 間の多対多のリレーショナリップの場合、Post または Tag を削除する前に PostTag ジョインレコードを削除してください。

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 を積極的にロードします。