#1 ๊ฐ์
์ด์ ๊ฒ์๊ธ์ ์ด์ด, Room์ ๋จ์ ๋ถ๋ถ์ ๊ตฌํํ๋ค.
#2 ์ฝ๋
#2-1 @DAO
// package com.example.nutri_capture_new.db
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import java.time.LocalDate
@Dao
interface MainDAO {
@Query("SELECT day_id FROM day_table WHERE day_date = :date LIMIT 1")
suspend fun getDayId(date: LocalDate): Long?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertDay(day: Day): Long
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertMeal(meal: Meal): Long
@Delete
suspend fun deleteMeal(meal: Meal): Int
@Query("""
SELECT meal_table.*
FROM meal_table
INNER JOIN day_table ON meal_table.day_id = day_table.day_id
WHERE day_table.day_date = :targetDate
ORDER BY meal_table.meal_time ASC
""")
suspend fun getMealsOrderedByTime(targetDate: LocalDate): List<Meal>
@Query("SELECT COUNT(*) FROM meal_table WHERE day_id = :dayId")
suspend fun getMealCountForDay(dayId: Long): Int
@Query("DELETE FROM day_table WHERE day_id = :dayId")
suspend fun deleteDay(dayId: Long)
}
์ฒ์๋ถํฐ ์ด ๋ชจ๋ ํจ์๋ค์ ์๊ฐํด๋ธ ๊ฒ์ ์๋๋ค. ๋ณธ ๊ฒ์๊ธ ์ดํ ๊ฒ์๊ธ์์ INSERT, SELECT ๋ฑ์ View์์๋ถํฐ Triggerํ๋ ์ฝ๋๋ฅผ ๋ง๋ค์๋๋ฐ ํด๋น ์ฝ๋๋ฅผ ๋ง๋ค๋ฉฐ ์ด DAO์ ํจ์๋ค๊ณผ ์๋์ ์๋ Repository์ ํจ์๋ค์ ํ๋ํ๋ ๋ง๋ค์ด๋๋ค. ์ฆ, ์ง๊ธ์ @Dao ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ์ธํฐํ์ด์ค ํ๋๋ง ์ ์ํ๊ณ ๋์ด๊ฐ๋ ์๊ด์ด ์๋ค๋ ๋ง์ด๋ค.
#2-2 Repository
// package com.example.nutri_capture_new.db
import java.time.LocalDate
class MainRepository(private val dao: MainDAO) {
suspend fun insertMeal(meal: Meal, date: LocalDate): Long {
var dayId = dao.getDayId(date)
if (dayId == null) {
dayId = dao.insertDay(Day(date = date))
}
return dao.insertMeal(meal.copy(dayId = dayId))
}
suspend fun deleteMeal(meal: Meal): Int {
val deletedRowCount = dao.deleteMeal(meal)
if (deletedRowCount == 0) {
return 0
} else {
val mealCount = dao.getMealCountForDay(meal.dayId)
if (mealCount == 0) {
dao.deleteDay(meal.dayId)
}
return deletedRowCount
}
}
suspend fun getMealsOrderedByTime(targetDate: LocalDate): List<Meal> {
return dao.getMealsOrderedByTime(targetDate)
}
}
insertMeal( ... )
Meal์ INSERTํ๋ ค๊ณ ์๋ํ ๋ ๋ถ๋ชจ ํ ์ด๋ธ ์ฆ, Day ํ ์ด๋ธ์ด ์กด์ฌํ์ง ์์ผ๋ฉด ์๋ฌ๊ฐ ๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์, Day ํ ์ด๋ธ์ด ์๋ค๋ฉด ๋จผ์ Day ํ ์ด๋ธ๋ถํฐ ์์ฑํ๋ ์ฝ๋๋ฅผ ์ง์ด๋ฃ๋๋ค.
deleteMeal( ... )
Meal์ด ํ๋๋ ์๋ Day๋ ์กด์ฌ ์ด์ ๊ฐ ์๋ค. ๋ฐ๋ผ์, Meal์ด ํ๋๋ ์๋ค๋ฉด Day ํ ์ด๋ธ์ ์ญ์ ํ๋ค.
getMealsOrderedByTime( ... )
์ด๋ค ๋ (Day)์ ๋จน์ ๊ฒ๋ค(List<Meal>)์ ์ค๋ฆ์ฐจ์(#2-1์ DAO ์ฝ๋ ์ฐธ์กฐ)์ผ๋ก ๊ฐ์ ธ์จ๋ค.
#2-3 TypeConverter
Room์ ์ฌ์ฉํ์ฌ ๋ณต์กํ ๋ฐ์ดํฐ ์ฐธ์กฐ | Android Developers
์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. Room์ ์ฌ์ฉํ์ฌ ๋ณต์กํ ๋ฐ์ดํฐ ์ฐธ์กฐ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. Room์ ๊ธฐ๋ณธ ์ ํ๊ณผ
developer.android.com
Room์ LocalDateํ ๋ฐ LocalTimeํ ๋ณ์๋ฅผ ๋ด๋ถ์ ์ผ๋ก ์ ์ฅํ์ง ๋ชปํ๋ค. ๋ฐ๋ผ์ ์ ๊ณต์๋ฌธ์์ ๊ฐ์ด๋๋ฅผ ๋ฐ๋ผ ์๋ ์๋ TypeConverter ํด๋์ค๋ฅผ ๋ง๋ค์๋ค.
// package com.example.nutri_capture_new.db
import androidx.room.TypeConverter
import java.time.LocalDate
import java.time.LocalTime
import java.time.format.DateTimeFormatter
class Converters {
private val dateFormatter = DateTimeFormatter.ISO_LOCAL_DATE
private val timeFormatter = DateTimeFormatter.ISO_LOCAL_TIME
// LocalDate -> String
@TypeConverter
fun fromLocalDate(date: LocalDate?): String? {
return date?.format(dateFormatter)
}
// String -> LocalDate
@TypeConverter
fun toLocalDate(dateString: String?): LocalDate? {
return dateString?.let { LocalDate.parse(it, dateFormatter) }
}
// LocalTime -> String
@TypeConverter
fun fromLocalTime(time: LocalTime?): String? {
return time?.format(timeFormatter)
}
// String -> LocalTime
@TypeConverter
fun toLocalTime(timeString: String?): LocalTime? {
return timeString?.let { LocalTime.parse(it, timeFormatter) }
}
}
#2-4 @Database
// package com.example.nutri_capture_new.db
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
@Database(
entities = [
Day::class,
Meal::class
],
version = 1
)
@TypeConverters(Converters::class)
abstract class MainDatabase : RoomDatabase() {
abstract val mainDAO: MainDAO
companion object {
@Volatile
private var INSTANCE: MainDatabase? = null
fun getInstance(context: Context): MainDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
MainDatabase::class.java,
"main_database"
).build()
INSTANCE = instance
}
return instance
}
}
}
}
์ด ๊ฒ์๊ธ์ ์๋ Database ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ค. #2-3์์ ๋ง๋ TypeConverter๋ฅผ ์ถ๊ฐํ๋ ๊ตฌ๋ฌธ(@TypeConverters(Converters::class))๋ ๋ฃ์ด์ค๋ค.
#3 ์์ฝ
Room์ Entity ๋ถ๋ถ์ ์ ์ธํ ๋๋จธ์ง(Dao์ Database ๊ทธ๋ฆฌ๊ณ TypeConverter์ Repository)๋ฅผ ๊ตฌํํ๋ค.
#4 ์์ฑ๋ ์ฑ
#4-1 ์ด ๊ฒ์๊ธ ์์ ์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com
#4-2 ๋ณธ ํ๋ก์ ํธ์ ๊ฐ์ฅ ์ต์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com
'๊ฐ๋ฐ ์ผ์ง ๐ป > Nutri Capture' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Nutri Capture ๋ฐฑ์๋ - View์์ INSERT ํธ๋ฆฌ๊ฑฐ (0) | 2024.10.23 |
---|---|
Nutri Capture ๋ฐฑ์๋ - Model์ ViewModel์ ์์ฑ์ ์ฃผ์ (0) | 2024.10.23 |
Nutri Capture ๋ฐฑ์๋ - ์ ERD์ Room์ @Entity ์ ์ (1) | 2024.10.23 |
Nutri Capture ํ๋ก ํธ์๋ - Card (0) | 2024.10.17 |
Nutri Capture ํ๋ก ํธ์๋ - ์คํฌ๋กค ๋ก์ง View์ ์ผ์ (0) | 2024.10.16 |