【SwiftUI】Core Dataの使い方:リレーションシップ編

リレーションシップを使ってエンティティ同士をリンクする方法を解説します。

スポンサーリンク

環境

この記事の情報は次のバージョンで動作確認しています。

【Xcode】12.4
【Swift】5.3.2
【iOS】14.4
【macOS】Big Sur バージョン 11.1
スポンサーリンク

リレーションシップの設定

リレーションシップとは、レコード(オブジェクト)に別のエンティティのオブジェクトを関連付ける仕組みです。

1対1のリレーション

例として次のような2つのテーブルの関係を考えてみます。

図:1対1のリレーション

生徒が所属するクラブを、Clubテーブルへのリレーションシップで表した例です。
一人の生徒が所属できるのは1つのクラブだけです。

これをエンティティの定義に置き換えて見ましょう。

Clubエンティティは次の通りです。

Image002

Studentエンティティの所属クラブを示す項目(club)は、次のようにRelationshipとして定義します。Destination(接続先)はClubエンティティを指定します。

図:Studentエンティティ

これで、StudentからClubへのリレーションシップが定義できました。

1対多のリレーション

Student側からだけでなく、Club側からStudentへの関係も辿れた方が便利ですね。
ClubからStudentへのリレーションシップも定義してみましょう。

ClubエンティティのRelationshipに、所属する生徒を表すstudentsを定義し、Destination(接続先)にStudentエンティティを指定します。

図:studentsリレーションシップの定義

1つのクラブに対して所属できる生徒は複数いますので、1対多の関係する必要があります。
studentsのInspectorを開き、TypeをデフォルトのTo OneからTo Manyに変更します。
これでリレーションシップstudentsはStudentオブジェクトを複数所持可能なリストとして定義されます。

Image005

これでClubからStudentへのリレーションシップが設定完了です。
2つのテーブルの関係は次にようになります。

図:2つのテーブルの関係

相互リレーション

上記で設定した2つのリレーションの相互リレーション(Inverse)を定義すると、片方のオブジェクトを追加/削除した場合、関係するリレーションが自動で更新されるようになります。
こちらは原則定義しておきましょう。(この定義が無いとBuild時にWarningが出ます)

リレーションシップstudentsのInverseをclubに設定します。

Image007

反対側のStudentsエンティティを見ると、リレーションシップclubのInverseが自動的に設定されているのがわかります。

図:Inverseの設定

これで、相互リレーションの定義が完了です。

スポンサーリンク

リレーションデータの登録

次に、リレーションデータの登録方法を解説します。
次の初期データ登録処理(RegistSampleData.swift)をプロジェクトに追加して下さい。

1対1のリレーション追加

リレーションの追加処理はコードの次の部分です。

Clubテーブルより対象となるクラブのレコードを検索し、新規に作成したStudentオブジェクトに関連付けています。
StudentからみたClubは1対1の関係です。(生徒一人が所属するクラブは1つのみ)

1対nのリレーション追加

StudentとClubは相互リレーションの関係ですので、逆からのリレーション追加も可能です。
先程のコードを次にのように変更しても、同じ結果が得られます。
※強調部分が変更点です

ClubからみたStudentは1対nの関係(1つのクラブに所属する生徒は複数)ですので、リレーションはコレクション形式で保持されます。
追加/削除にはアクセサメソッドを使用します。
Clubエンティティのソース(Club+CoreDataProperties.swift)を手動生成して確認すると、Club.studentsに登録・削除する為の、次のようなアクセサメソッドが追加されているのがわかります。
(※コードの手動生成方法は 【SwiftUI】Core Dataの使い方:エンティエィ(Entity)を定義する を参照して下さい。)

スポンサーリンク

リレーションデータの取得

次にリレーションデータの取得方法を解説します。

1対1のリレーション取得

Studentテーブルから関連するClubテーブルの情報を検索する例です。
1対1のリレーション取得になります。

結果画面

次の箇所が、リレーションの取得部分になります。
リレーションを示すstudent.clubがClubオブジェクトそのものです。

1対nのリレーション取得

こちらはClubテーブルから関連するStudentテーブルの情報を検索する例です。
1対nのリレーション取得になります。

結果画面

Studentテーブルへのリレーションを示す club.students は、順序付けされていないコレクションクラスであるNSSet型なので、次の関数でStudentの配列に変換しています。

今回はサンプルとしてわかりやすいように、ContentViewのプライベート関数としましたが、次のようにClubエンティティクラス(Club+CoreDataProperties.swift)の計算プロパティとして追加した方が使い勝手が良いでしょう。

スポンサーリンク

合わせて読みたい記事

【SwiftUI】Core Dataの使い方:標準テンプレートを読み解く
(2023/03/25 更新) SwiftUIでのCore Dataの使い方を、標準テンプレートを読み解きながら解説します。
【SwiftUI】Core Dataの使い方:エンティエィ(Entity)を定義する
(2021/04/26 更新) Xcodeでエンティティを定義する方法を解説します。
【SwiftUI】Core Dataの使い方:準備編
SwiftUIでCore Dataを扱うための前提知識と、新規プロジェクトの作成方法について解説します。
【SwiftUI】Core Dataの使い方:基本編
SwiftUIでCore Dataの基本的な使い方を簡単なTodoリストアプリを例に解説します。
【SwiftUI】Core Dataの使い方:検索編(1/3)
データベースを検索して、オブジェクトとして取得するfetch処理について解説します。 を先に見ておくことをおすすめします。
【SwiftUI】Core Dataの使い方:検索編(2/3)
検索条件を動的に変更する方法を解説します。 の続編です。
【SwiftUI】Core Dataの使い方:検索編(3/3)
前の2つの記事 では、SwiftUIの特徴であるデータバインディングの仕組みを使い、検索結果とViewを紐付ける方法を紹介しました。これにより、検索結果に応じてViewが自動で再描画されます。 しかし、検索結果を別の処理のインプットに使う場...