はじめに
CoreDataでリレーションシップの機能を使ったので備忘録として残します。
前半は関係データベースについて、後半はCoreDataでの関係データベース設定方法について記述します。
環境
- Swift: version 5.6
- Xcode: Version 13.3.1 (13E500a)
- macOS: 12.3.1 (21E258)
リレーションシップ(Relationship)とは?
エンティティ(Entity)同士の関係性。
リレーションシップの設定を行うことで関係データベースを構築することができる。
関係データベース
データを表で管理するデータベースのこと。
行(レコード)と列(属性)で構成される。
- データのが追加されると行が増える。
- 行には名前がないが、列には名前(属性名)がある
主キー
表の中からある特定の行を識別するための列。
主キーの条件
- データの重複がないこと。
- データが空でないこと。
複合主キー
複数の列を組み合わせてつくる主キーのこと。
上記の主キーの条件を満たす列がない場合に使用する。
外部キー
別の表の主キーを参照する列のこと。
正規化
データが重複したり、データの更新の際に矛盾が生じたりしないように表をわけること。
関係データベースを構築する
今回もポケモンを使って考えてみます。
ボックスと預けているポケモンの関係性が使えそうです。
こんなイメージ。
1. Entityの作成
2. Attributesの追加
3. Relationshipの追加
関係性の設定
Box
側
1つのボックスには複数のポケモンを預けることができます。
なのでTo Many
(1対多)に設定します。
Pokemon
ポケモンは1つのボックスにだけ預けることができます。
なのでTo One
(1対1)に設定します。
以上でCoreDataの設定は完了です。
データベースの使い方
関係する部分だけを載せています。
いないとは思いますが、他の部分が気になる方はGitHubのこちらのリポジトリに保存していますのでよかったら見て下さい。
(独学だから誰か見て評価して欲しい。。)
データの保存
import SwiftUI
struct RegistPokemonView: View {
@Environment(\.colorScheme) private var colorScheme
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Box.boxNo, ascending: true)],
animation: .default)
private var boxs: FetchedResults<Box> //ボックスデータの呼び出し
@State var boxNo: Box? //ピッカーで選択したボックスを格納
let pokemon: PokemonJSONModel //ポケモンの情報
var body: some View {
/*省略*/
}
private func saveCoreData() { //預けるボタン押下時に実行
if let box = box {
let newPokemon = Pokemon(context: viewContext)
newPokemon.id = UUID()
newPokemon.name = pokemon.name
newPokemon.pokedexNo = Int64(pokemon.no)
newPokemon.boxNo = box //ポケモンとボックスの紐付け
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
ボックスのデータは予め用意しています。
データの紐付けは代入操作で行います。
このとき、boxNo
の型はBox?
型になっていました。
(Int
型じゃなかった。手書きの図のイメージであってるのか不安。)
UI部分は省略しましたがこんな感じです。
預けるボタンを押すとボックスに追加されます。
データの更新と削除
import SwiftUI
struct EditPokemonView: View {
@Environment(\.colorScheme) private var colorScheme
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Box.boxNo, ascending: true)],
animation: .default)
private var boxies: FetchedResults<Box>
@State private var boxNo: Box? //変更先のボックスを格納
let pokemon: Pokemon //ポケモンの情報
var body: some View {
/*省略*/
}
private func saveCoreData() { //保存ボタン押下時に実行
do {
pokemon.boxNo = boxNo //変更先のボックスを代入
try viewContext.save() //保存(更新)処理
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
private func deleteCoreData() { //逃がすボタンを押下時に実行
viewContext.delete(pokemon) //削除処理
}
}
更新時はPokemon.boxNo
に別のBox
を代入してやればOKです。
.save()
メソッドの呼び出しは忘れずに。
削除時は.delete(_:)
メソッドの呼び出しだけでOKです。
この時ポケモンのデータがなくなるだけで、紐付いているボックスはなくなりません。
保存を押すとボックスを移動します。
逃がすを押すといなくなります。。
さいごに
今回はCoreDataでの関係データベース構築についてまとめてみました。
学びたてなので間違っていればご指摘お願いします。
最後までご覧いただきありがとうございました。
参考記事・書籍