#1 ๊ฐ์
#1-1 ์ด์ ๊ฒ์๊ธ ํ๊ธฐ
ERD์ ๋ํด ๋ค๋ค๋ ์ด์ ๊ฒ์๊ธ์ ์ฑ์ ๋ฐฉํฅ์ฑ์ ์ฌ๊ณ ํ ์ด ๊ฒ์๊ธ๊ณผ ์์ถฉ๋๋ค. ๋ฐ๋ผ์ ์ด์ ์ ๋ง๋ค์๋ ERD๋๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์คํค๋ง๋ฅผ ํ์ฑํ์ง ์์ ๊ฒ์ด๋ค. ์ ERD๋ ์๋์ ๊ฐ๋ค.
#1-2 ์ ERD
meal_table๊ณผ nutrition_info_table์ด 1 : n ๊ด๊ณ์ธ ๊ฒ์ฒ๋ผ ๋์ด์๋๋ฐ ์ค์ ๋ก๋ ๊ทธ๋ ์ง ์๋ค. nutrition_info_table์ meal_table์ ๊ธฐ๋ณธํค๋ฅผ ์ธ๋ํค์ด์ ๊ธฐ๋ณธํค๋ก ์ฐ๋, ์๋ณ ๊ด๊ณ์ ์์ ํ
์ด๋ธ์ด๊ธฐ ๋๋ฌธ์ 1 : 1 ๊ด๊ณ๋ค. ์ ERD ์ด๋ฏธ์ง๋ DBeaver๋ฅผ ํตํด ๋ฝ์๋ธ ๊ฒ์ธ๋ฐ ์๋ง ์ค๋ฅ๊ฐ ๋ ๊ฒ ๊ฐ๋ค. ์๋๋ฉด 1..n๋ผ๋ ํ๊ธฐ๊ฐ 1 : 1๊ณผ 1 : n์ ๋ชจ๋ ์์ฐ๋ฅด๋ ํํ์์ผ๊น? ์๋ฌดํผ ๊ทธ๋ ๋ค.
-- Day ํ
์ด๋ธ
CREATE TABLE "day_table" (
"day_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"date" TEXT NOT NULL
);
-- Meal ํ
์ด๋ธ
CREATE TABLE "meal_table" (
"meal_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"day_id" INTEGER NOT NULL,
"time" TEXT NOT NULL,
"name" TEXT NOT NULL,
-- Foreign key ์ค์
FOREIGN KEY ("day_id") REFERENCES "day_table" ("day_id") ON DELETE CASCADE
);
-- NutritionInfo ํ
์ด๋ธ
CREATE TABLE "nutrition_info_table" (
"meal_id" INTEGER PRIMARY KEY NOT NULL,
"overeating_excess" INTEGER NOT NULL, -- ๊ณผ์ ์ ๋๊ฐ
"refined_sugar_excess" INTEGER NOT NULL, -- ์ ์ ๋น ์ญ์ทจ ์ ๋๊ฐ
"refined_grain_excess" INTEGER NOT NULL, -- ์ ์ ๊ณก๋ฌผ ์ญ์ทจ ์ ๋๊ฐ
"flour_excess" INTEGER NOT NULL, -- ๋ฐ๊ฐ๋ฃจ ์ญ์ทจ ์ ๋๊ฐ
"fiber_quality" INTEGER NOT NULL, -- ์ฌ์ ์ง ์ญ์ทจ ์ ๋๊ฐ
"protein_quality" INTEGER NOT NULL, -- ๋จ๋ฐฑ์ง ์ญ์ทจ ์ ๋๊ฐ
"sodium_excess" INTEGER NOT NULL, -- ๋ํธ๋ฅจ ์ญ์ทจ ์ ๋๊ฐ
-- Foreign key ์ค์ (Meal๊ณผ ์๋ณ ๊ด๊ณ)
FOREIGN KEY ("meal_id") REFERENCES "meal_table" ("meal_id") ON DELETE CASCADE
);
๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง๋ฅผ SQLite์ SQL๋ฌธ์ผ๋ก ๋ณด๋ฉด ์์ ๊ฐ๋ค. NutritionInfo ํ
์ด๋ธ์ Column๋ค์ ์ฌ๊ธฐ์์ ๋์ถํ๋ ๊ฑธ ๋ฃ์์ผ๋ฉฐ ์์ผ๋ก ๊ณ์ ์
๋ฐ์ดํธํด ๋๊ฐ ๊ฒ์ด๋ค. ๋ง์์๋ก ๋์๊ฑฐ์๋ Excess, ๋ง์์๋ก ์ข์๊ฑฐ์๋ Quality๋ฅผ ๋ถ์ด๋ ๊ท์น์ ๋์๋ค. ์ธ๋ฐ์์ด ๋ณ์์ด๋ฆ์ ๊ธธ์ด๋ฅผ ๋๋ฆฌ๋ ๊ท์น์ด ๋ ์๋ ์๊ฒ ์ผ๋, ๋ ์ง๊ด์ ์ธ ์๋ฏธ๋ฅผ ์๋ ค์ฃผ๋ ์ฅ์ ๋ ์๋ค๊ณ ์๊ฐํด์ ๋ง๋ค์๋ค. ์ด ๊ท์น์ด ๋์ค์ ๋ถํ์ํ๋ค๊ณ ํ๋จ๋๋ฉด ์์ ๊ฒ ๋ค.
#1-3 Room ๋ผ์ด๋ธ๋ฌ๋ฆฌ
[Android] Room - ๊ธฐ์ด, INSERT์ DELETE ์ฐ์ต
#1 Room ์๊ฐ Room์ ์ฌ์ฉํ์ฌ ๋ก์ปฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ ์ ์ฅ | Android DevelopersRoom ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ ์ฝ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ ์งํ๋ ๋ฐฉ๋ฒ ์์๋ณด๊ธฐdeveloper.android.comSQLite๋ ๋ชจ๋ฐ์ผ ๊ธฐ๊ธฐ๋ฅผ ์ํ SQL
kenel.tistory.com
Room์ ๊ดํ ๋ด์ฉ์ ์ ๊ฒ์๊ธ์ ๊ธฐ๋ฐํ์ฌ ์์ฑํ๋ค.
#2 ์ฝ๋ - Entity์ฉ data class ๋ง๋ค๊ธฐ
#2-1 ๊ฐ์
๋ค์ ๊ฒ์๊ธ์์ Room์ @Entity ์ด๋
ธํ
์ด์
๋ฑ์ ์ด์ฉํด ๋ฐ์ดํฐ๋ฒ ์ด์ค Entity๋ก ๋ง๋ค ํด๋์ค์ ๋ด์ฉ์ ๋ฏธ๋ฆฌ ์์ฑํ๋ค. #2-2 ~ #2-4์ ์๋ data class๋ค์ ๋ชจ๋ "db"๋ผ๋ ์๋ก์ด ํจํค์ง๋ฅผ ๋ง๋ค์ด ์์น์ํจ๋ค.
#2-2 Day
// package com.example.nutri_capture_new.db
import java.time.LocalDate
data class Day(
val dayId: Long = 0,
var date: LocalDate,
)
#2-3 Meal
// package com.example.nutri_capture_new.db
import java.time.LocalTime
data class Meal(
val mealId: Long = 0,
// ์ธ๋ํค
val dayId: Long = 0,
var time: LocalTime,
var name: String,
val nutritionInfo: NutritionInfo,
)
#2-4 NutritionInfo
// package com.example.nutri_capture_new.db
import androidx.room.ColumnInfo
data class NutritionInfo(
// ๊ณผ์ ์ ๋๊ฐ
@ColumnInfo(name = "overeating_excess")
var overeatingExcess: Int = 0,
// ์ ์ ๋น ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "refined_sugar_excess")
var refinedSugarExcess: Int = 0,
// ์ ์ ๊ณก๋ฌผ ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "refined_grain_excess")
var refinedGrainExcess: Int = 0,
// ๋ฐ๊ฐ๋ฃจ ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "flour_excess")
var flourExcess: Int = 0,
// ์ฌ์ ์ง ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "fiber_quality")
var fiberQuality: Int = 0,
// ๋จ๋ฐฑ์ง ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "protein_quality")
var proteinQuality: Int = 0,
// ๋ํธ๋ฅจ ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "sodium_excess")
var sodiumExcess: Int = 0
)
์๋ "nutrient" ํจํค์ง์ ์๋ ํด๋์ค๋ค. "db" ํจํค์ง๋ก ์ฎ๊ธฐ๊ณ , ์์ฑ์ ํ๋กํผํฐ๋ค๋ ์์ ๊ฐ์ด ์
๋ฐ์ดํธํ๋ค.
#3 ์ฝ๋ - Entity ๋ง๋ค๊ธฐ
#3-1 Room ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ค์ด๋ก๋
ํ๋ก์ ํธ ์์ค build.gradle
plugins {
...
// KSP (์ด๋
ธํ
์ด์
์ฝ๊ธฐ์ฉ)
id("com.google.devtools.ksp") version "1.9.0-1.0.13" apply false
}
#1-3์ ์๋ Room ๊ฒ์๊ธ๊ณผ๋ ๋ฌ๋ฆฌ, ์ด๋
ธํ
์ด์
์ฝ๊ธฐ๋ฅผ ์ํด kapt ๋์ KSP๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ค.
๋ชจ๋ ์์ค build.gradle
plugins {
...
// KSP (์ด๋
ธํ
์ด์
์ฝ๊ธฐ์ฉ)
id("com.google.devtools.ksp")
}
android {
...
}
dependencies {
...
// Room
implementation (libs.androidx.room.runtime)
implementation (libs.androidx.room.ktx)
// KSP (์ด๋
ธํ
์ด์
์ฝ๊ธฐ์ฉ)
ksp(libs.androidx.room.compiler)
}
libs.versions.toml
[versions]
...
roomVersion = "2.6.1"
[libraries]
...
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomVersion" }
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomVersion" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomRuntime" }
[plugins]
...
#3-2 Day
// package com.example.nutri_capture_new.db
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import java.time.LocalDate
@Entity(
tableName = "day_table",
indices = [Index(value = ["day_date"], unique = true)]
)
data class Day(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "day_id")
val dayId: Long = 0,
@ColumnInfo(name = "day_date")
var date: LocalDate,
)
indices๋ฅผ ํตํด date๋ฅผ ์ธ๋ฑ์ฑํ ์ด์ ๋, date๋ฅผ unique = true ์์ฑ์ ๋ถ์ฌํ๊ธฐ ์ํ ์ ํ ์กฐ๊ฑด์ด๊ธฐ ๋๋ฌธ์ด๋ค. ๋น์ฐํ์ง๋ง, ์ด ํ๋ก์ ํธ์์ date์ ์ค๋ณต์ด ๋ฐ์ํด์ ์ ๋๋ค.
#3-3 Meal
// package com.example.nutri_capture_new.db
import androidx.room.ColumnInfo
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import java.time.LocalTime
@Entity(
tableName = "meal_table",
foreignKeys = [
ForeignKey(
entity = Day::class,
parentColumns = ["day_id"],
childColumns = ["day_id"],
onDelete = ForeignKey.CASCADE
)
]
)
data class Meal(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "meal_id")
val mealId: Long = 0,
// ์ธ๋ํค
@ColumnInfo(name = "day_id")
val dayId: Long = 0,
@ColumnInfo(name = "meal_time")
var time: LocalTime,
@ColumnInfo(name = "meal_name")
var name: String,
@Embedded
val nutritionInfo: NutritionInfo,
)
@Embedded๋ ์ด๋ค ๊ฐ์ฒด๋ฅผ ํต์งธ๋ก ๊ฐ์ ธ์ Column์ ๋ฃ๋ ๊ธฐ๋ฅ์ ํ๋ค. ์ฆ, ์ฌ์ค์ Meal์ Column์ ์ถ๊ฐํ๋ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ค. NutritionInfo๋ Meal์ ์๋ณ ๊ด๊ณ ์์ ํ
์ด๋ธ(#1-2์ ์๋ ๋์๋ ์ฐธ์กฐ)์ด๋ค. ์๋ณ ๊ด๊ณ ์์ ํ
์ด๋ธ์ ๋ถ๋ชจ ํ
์ด๋ธ์ Column์ ์ถ๊ฐํ๋ ๊ฒ๊ณผ ๊ฐ์ ์ญํ ์ ์ํํ๋ค. ๋ฐ๋ผ์, ์ ์ฝ๋์ ๊ฐ์ ๋ฐฉ์์ผ๋ก Room์ ์คํค๋ง๋ฅผ ์ง๋ฉด ์๋ณ ๊ด๊ณ๋ฅผ ํํํ ์ ์๋ ๊ฒ์ด๋ค.
#3-4 NutritionInfo
// package com.example.nutri_capture_new.db
import androidx.room.ColumnInfo
data class NutritionInfo(
// ๊ณผ์ ์ ๋๊ฐ
@ColumnInfo(name = "overeating_excess")
val overeatingExcess: Int = 0,
// ์ ์ ๋น ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "refined_sugar_excess")
val refinedSugarExcess: Int = 0,
// ์ ์ ๊ณก๋ฌผ ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "refined_grain_excess")
val refinedGrainExcess: Int = 0,
// ๋ฐ๊ฐ๋ฃจ ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "flour_excess")
val flourExcess: Int = 0,
// ์ฌ์ ์ง ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "fiber_quality")
val fiberQuality: Int = 0,
// ๋จ๋ฐฑ์ง ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "protein_quality")
val proteinQuality: Int = 0,
// ๋ํธ๋ฅจ ์ญ์ทจ ์ ๋๊ฐ
@ColumnInfo(name = "sodium_excess")
val sodiumExcess: Int = 0
)
@Entity๋ก์ ์๋ฆฝํ์ง ์๊ณ , @Embedded๋ฅผ ํตํด, Column๋ง Meal์ ์ ๋ฌ๋๋ค. ๋ฐ๋ผ์, @Entity ์ด๋
ธํ
์ด์
์ ์๊ณ , @ColumnInfo ์ด๋
ธํ
์ด์
๋ง ์กด์ฌํ๋ค.
#4 ์์ฝ
์ ERD์ ํด๋น ERD๋ฅผ ๊ตฌํํ๋ Room Entity๋ฅผ ๋ง๋ค์๋ค.
#5 ์์ฑ๋ ์ฑ
#5-1 ์ด ๊ฒ์๊ธ ์์ ์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com
#5-2 ๋ณธ ํ๋ก์ ํธ์ ๊ฐ์ฅ ์ต์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com