#1 개요
프로젝트의 데이터베이스(Room) 부분에서 작성했던 DAO 함수의 논리적 오류를 해결한다.
#2 논리적 오류 - ORDER BY
#2-1 문제 코드
...
@Dao
interface MainDAO {
...
@Query("SELECT * FROM DayMealView")
suspend fun getAllDayMeals(): List<DayMealView>
@Query("SELECT * FROM DayMealView LIMIT :limit")
suspend fun getAllDayMeals(limit: Int): List<DayMealView>
@Query("""
SELECT * FROM DayMealView
WHERE day_date <= :lastDate
AND meal_time <= :lastTime
AND meal_id != :lastId
LIMIT :limit
""")
suspend fun getNextDayMealsAfter(
lastDate: LocalDate,
lastTime: LocalTime,
lastId: Long,
limit: Int
): List<DayMealView>
@Query("SELECT * FROM DayMealView WHERE meal_id = :mealId LIMIT 1")
suspend fun getDayMeal(mealId: Long): DayMealView
}
데이터베이스는 복수의 레코드를 SELECT할 때, 정직하게 가져오지 않는다. 무슨 말이냐면, 레코드에 정렬된 순서 그대로를 지켜서 반환하지 않는다는 얘기다. DayMealView에 삽입되어있던 순서 그대로를 지켜서 반환된다고 생각하면 안 된다. 웬만하면 순서가 지켜겠지만 반드시 그렇지는 않다는 얘기다.
#2-2 해결
...
@Dao
interface MainDAO {
...
@Query("""
SELECT * FROM DayMealView
ORDER BY day_date DESC,
meal_time DESC,
meal_id DESC
""")
suspend fun getAllDayMeals(): List<DayMealView>
@Query("""
SELECT * FROM DayMealView
ORDER BY day_date DESC,
meal_time DESC,
meal_id DESC
LIMIT :limit
""")
suspend fun getAllDayMeals(limit: Int): List<DayMealView>
@Query("""
SELECT * FROM DayMealView
WHERE day_date <= :lastDate
AND meal_time <= :lastTime
AND meal_id != :lastId
ORDER BY day_date DESC,
meal_time DESC,
meal_id DESC
LIMIT :limit
""")
suspend fun getNextDayMealsAfter(
lastDate: LocalDate,
lastTime: LocalTime,
lastId: Long,
limit: Int
): List<DayMealView>
@Query("""
SELECT * FROM DayMealView
WHERE meal_id = :mealId
ORDER BY day_date DESC,
meal_time DESC,
meal_id DESC
LIMIT 1
""")
suspend fun getDayMeal(mealId: Long): DayMealView
}
ORDER BY문을 추가한다. getDayMeal()은 복수 개의 레코드를 가져오지 않기 때문에 ORDER BY문이 필요없다. 하지만, 머지않은 미래에 getDayMeal()를 복사ㆍ붙여넣기해 새로운 기능을 수행하는 DAO 함수를 추가할 것 같은 예감이 들기에 (실수 방지를 위해) 그냥 냅두겠다. 이 부분은 나중에 리팩토링을 목적으로 프로젝트를 처음부터 끝까지 다듬을 때 수정될 것이다.
#3 논리적 오류 - AND
#3-1 문제 상황
... | meal_id | day_date | meal_time | ... |
... | ... | ... | ... | ... |
... | 81 | 2024-11-25 | 09:50:57.13994 | ... |
... | 80 | 2024-11-13 | 18:41:07.954925 | ... |
... | ... | ... | ... | ... |
'meal_id가 80인 레코드' 다음 레코드인 'meal_id가 81인 레코드'가 LazyColumn 상에서 Load되지 않는 문제가 발생했다. 이것만 봐서는 문제의 원인을 알 수 없었지만, day_date가 차이난다는 점에서 뭔가 잘못되지 않았나 추측이 된다.
#3-2 문제 코드
...
@Dao
interface MainDAO {
...
@Query("""
SELECT * FROM DayMealView
WHERE day_date <= :lastDate
AND meal_time <= :lastTime
AND meal_id != :lastId
ORDER BY day_date DESC,
meal_time DESC,
meal_id DESC
LIMIT :limit
""")
suspend fun getNextDayMealsAfter(
lastDate: LocalDate,
lastTime: LocalTime,
lastId: Long,
limit: Int
): List<DayMealView>
...
}
문제는 AND의 남발이었다. date가 작거나 같으면서 동시에 time이 작거나 같으면서 동시에 meal_id는 달라야한다는 조건. 이 조건은 AND의 나열로 구성되었는데, 이러면 내가 정확히 원하는 조건과 논리적으로 다른 조건이 된다.
DayMealView는 1차로 date에 대해 내림차순으로 정렬하고, date가 같으면 time에 대해 time마저 같으면 id에 대해 내림차순으로 정렬하는 테이블이며, 이 테이블의 정렬 조건을 준수하여 WHERE문을 작성했어야 했다. 제대로 다시 쿼리의 WHERE문을 수정해 내가 정확히 원하는 조건과 같게 만들어본다.
#3-3 해결
...
@Dao
interface MainDAO {
...
@Query("""
SELECT * FROM DayMealView
WHERE day_date < :lastDate
OR (day_date = :lastDate AND meal_time < :lastTime)
OR (day_date = :lastDate AND meal_time = :lastTime AND meal_id < :lastId)
ORDER BY day_date DESC,
meal_time DESC,
meal_id DESC
LIMIT :limit
""")
suspend fun getNextDayMealsAfter(
...
): ...
...
}
#3-2에서 말한 내가 정확히 원하는 조건 그대로를 쿼리문에 넣었다. WHERE 문이 DayMealView의 정렬 조건을 준수하게 만든 것이다.
#4 완성된 앱
#4-1 이 게시글 시점의 Commit
#4-2 본 프로젝트의 가장 최신 Commit
'App 개발 일지 > Nutri Capture' 카테고리의 다른 글
Nutri Capture 프론트엔드 - INSERT 및 DELETE 버튼 구현 (1) | 2024.11.28 |
---|---|
Nutri Capture 백엔드 - DeleteDayMeal 이벤트 추가 (0) | 2024.11.28 |
Nutri Capture 프론트엔드 - 무한 스크롤 로직 리팩토링 (0) | 2024.11.16 |
Nutri Capture 백엔드 - Room 무결성 보완 (1) | 2024.11.15 |
Nutri Capture 프론트엔드 - 채팅UI 구조 잡기 (0) | 2024.11.14 |