이번에 프로젝트를 하게 되면 Room을 이용해 DB를 적용해 보았습니다.
처음에는 이러한 구조로 entity들을 설계하였습니다. 이렇게 만들려고 하니 Room에서 외래키의 연결이 잘못돼있다면서 787 에러를 보여줬습니다. 위의 구조의 경우 순환 참조가 일어납니다. 모든 테이블이 연결돼있으므로 참조할 수 없게 되는 현상이 생깁니다. 그래서 해당 참조를 끊어줘야 합니다. 이관계에서는 사실상 과정테이블의 경우 budgetNum은 필요가 없습니다. 편의를 위해 만든 것일 뿐 해당 과정이 어떤 가계부에 속해있는지는 부모인 카테고리를 따라 올라가다 보면 가계부를 찾을 수 있습니다.
변환시킨 DB 구조입니다. 이 구조를 코드로 만들면
@Entity(
tableName = "BUDGET",
)
data class Budget(
@ColumnInfo(name = "NAME")
val name: String,
@ColumnInfo(name = "START_DATE")
val startDate: String,
@ColumnInfo(name = "END_DATE")
val endDate: String,
@ColumnInfo(name = "MONEY")
val money: Int,
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "NUM")
val num: Int = 0,
)
@Entity(
tableName = "CATEGORY",
foreignKeys = [
ForeignKey(
entity = Budget::class,
parentColumns = ["NUM"],
childColumns = ["BUDGET_NUM"],
onDelete = ForeignKey.CASCADE
)
]
)
data class Category(
@ColumnInfo(name = "BUDGET_NUM")
val budgetNum: Int,
@ColumnInfo(name = "NAME")
val name: String,
@ColumnInfo(name = "COLOR")
val color: String,
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "NUM")
val num: Int = 0,
)
@Entity(
tableName = "PROCEDURE",
foreignKeys = [
ForeignKey(
entity = Category::class,
parentColumns = ["NUM"],
childColumns = ["CATEGORY_NUM"],
onDelete = ForeignKey.CASCADE
)
]
)
data class Procedure(
@ColumnInfo(name = "CATEGORY_NUM")
val categoryNum: Int,
@ColumnInfo(name = "NAME")
val name: String,
@ColumnInfo(name = "DESCRIPTION")
val description: String,
@ColumnInfo(name = "MONEY")
val money: Int,
@ColumnInfo(name = "TIME")
val time: String,
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "NUM")
val num: Int = 0,
)
이런 식으로 짤 수 있습니다. 또한 위와 같이 Foreign키가 연결돼있다면 연결된 값들은 한 번에 가져올 수도 있습니다.
data class BudgetCategories(
@Embedded
val budget: Budget,
@Relation(
parentColumn = "NUM",
entityColumn = "BUDGET_NUM"
)
val categories: List<Category>?,
)
@Dao
interface BudgetCategoriesDao {
@Transaction
@Query("SELECT * FROM BUDGET")
suspend fun getAllBudgetCategories(): List<BudgetCategories>
@Transaction
@Query("SELECT * FROM BUDGET WHERE NUM = :num")
suspend fun getAllBudgetCategories(num: Int): List<BudgetCategories>
}
data class CategoryProcedures(
@Embedded
val category : Category,
@Relation(
parentColumn = "NUM",
entityColumn = "CATEGORY_NUM"
)
val procedures: List<Procedure>?,
)
@Dao
interface CategoryProceduresDao {
@Transaction
@Query("SELECT * FROM CATEGORY")
suspend fun getAllCategoryProcedures(): List<CategoryProcedures>
@Transaction
@Query("SELECT * FROM CATEGORY WHERE NUM = :num")
suspend fun getAllCategoryProceduresWithNum(num: Int): List<CategoryProcedures>
@Transaction
@Query("SELECT * FROM CATEGORY WHERE BUDGET_NUM = :budgetNum")
suspend fun getAllCategoryProceduresWithBudgetNum(budgetNum: Int): List<CategoryProcedures>
}
이런 식으로 Embedded, Relation, Transaction 등을 이용하여 각각 연동되어 있는 값들을 Dao로 받아올 수 있습니다.
이렇게 외래키를 사용할 때 주의할 점은 예를 들어 카테고리를 추가한다고 하면 가계부테이블에 있는 것을 부모로 둬야 합니다. 없는 부모를 넣게 되면 오류가 생기 때문에 이점을 주의해야 합니다.
'안드로이드 > 안드로이드' 카테고리의 다른 글
[Android/Kotlin] 알림(Notification) - 2, 알림의 속성 (1) | 2023.10.29 |
---|---|
[Android/UI] BackGroundTint 값 Hex값으로 설정 (0) | 2023.10.16 |
[Android/Kotlin] ViewModel 과 ViewPager (1) | 2023.10.10 |
[Android/Kotlin] SharedPreferences (0) | 2023.09.14 |
[Android/Kotlin] DialogFragment 크기조절 (0) | 2023.09.13 |