본문 바로가기
개인 프로젝트/운동일지 App

[kotlin] 운동 일지 App 개발일지 #03

by 왕큰새 2022. 2. 4.
728x90

본격적으로 Room을 이용하여 삽입, 삭제, 수정을 적용시키고 있다.

1:N, M:N의 관계를 가진 Entity들을 삽입, 삭제, 조회 기능을 추가하였다.

 

현재 운동일지 App의 Entity Dialog 그램이다. 

 

루틴, 운동 Entity와 

루틴, 운동부위 Entity는 서로 M : N 의 관계를 가진다.

루틴이 삭제되어도 등록한 운동들은 삭제되지 않아야 하고, 운동 부위들도 삭제되지 않아야 하기 때문에

이런 관계를 가진다.

 

운동, 운동세트는 1:N의 관계를 가진다.

운동이 삭제되면, 운동세트도 사라진다.

 

 

한눈에 보기 쉽게 SQL WorkBench로 작성한 것이며, 실제 Room Database와 다르다.

 

운동일지 App Diagram

 

 

 

운동 추가 화면 루틴에 운동이 추가된 화면 운동 CardView 클릭

 

 

 

 운동 검색 창 체크된 운동이 루틴에 추가된 화면

 

 

 

루틴이 저장된 화면 루틴 수정하기 화면  루틴 삭제 화면 루틴이 삭제된 화면

글을 포스팅하면서 알았는데 새로 추가된 루틴이 맨 밑으로 가게 되어 있어서 수정해야 할 것 같다.

 

개발하면서 어려웠던 점은 루틴과 운동의 M:N 관계를 삽입하고 삭제하는 부분이였는데, 

이전에는 Routine Entity에 운동의 id를 String으로 이어붙여 Get하는 방식을 취하려 했으나

좋은 방법인 것 같지 않아서 M:N 으로 만드는 과정이 쉽지는 않았다.

 

Routine과 Exercise의 M:N 의 관계 Entity이다. 

운동에 RoutineId가 필요없기 때문에 이런식으로 구성하였다.

@Entity
data class Routine (
    @PrimaryKey(autoGenerate = true) val routineId:Long?,
    val name: String,
    )
@Entity(primaryKeys = ["routineId","exerciseId"])
data class RoutineExerciseCrossRef(
    val routineId: Long,
    val exerciseId: Long
)

data class RoutineWithExercises(
    @Embedded val routine: Routine,
    @Relation(
       parentColumn = "routineId",
       entityColumn = "exerciseId",
       associateBy = Junction(RoutineExerciseCrossRef::class)
    )
    val exercises: List<Exercise>
)

 

내 생각은 루틴을 먼저 삽입하고 InsertRoutine이 생성한 Routine의 Id를 리턴하니

그 리턴값을 받아서 현재 루틴에 추가되어 있는 운동들의 Id와 함께 

RoutineExerciseCrossRef  즉, 상호 참조 테이블을 만들면 되겠구나라고 생각했었다.

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertRoutine(routine: Routine):Long

 

하지만, Fragment 단에서는 Insert된 Routine 값을 가져올 수 없었고, 좋지 못한 방법이였다.

그래서 생각을 달리해 원래 Database에서 M:N의 관계를 가진 Entity를 Insert 할때를 생각해보니, 

생각보다 간단했다.

 

createRoutine 이라는 Insert 함수를 만들고, 여기서 insertRoutine을 실행하면서, 

같이 상호 참조 테이블을 Insert 하는 식으로 해결하였다.

잘 생각해보면 당연한 문제였는데 어디서부터 꼬였는지 생각이 이상한대로 흘러가서

생각보다 오래 걸린 문제였다.

@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun createRoutine(routine: Routine, exercises: List<Exercise>):Long {
        val routineId = insertRoutine(routine)
    exercises.map {
        it.exerciseId?.let {
            insertRoutineExerciseCrossRef(RoutineExerciseCrossRef(routineId,it))
        }
    }
    return routineId
}