본문 바로가기
Projects/It's My Waye

[It's My Waye] 4. DB 기능 구현 - Model 작성

by DevJaewoo 2022. 1. 22.
반응형

Model 작성

이제 설계한 DB를 바탕으로 테이블에 해당하는 Model을 만들어줘야 한다.

 

DB 설계
이전 글에서 설계한 DB

 

그림을 보면 Item과 Alarm이 1:1 관계이기 때문에, FK를 어느 테이블에 줘야 할지 선택해야 했다.

 

FK를 Item에 주면, Item 모델 내에 Alarm 변수를 두어 관리하고, 반대로 Alarm에 주면 Alarm 모델 내에 Item 변수를 만들어 관리해야 한다.

 

FK를 Item에 둔 경우

// Item
class Item(
    var name: String, 
    var enabled: Boolean, 
    var alarm: Alarm? = null) {}

// Alarm
class Alarm(
    var filePath: String,
    var volume: Int = 100,
    var repeatTimes: Int = 20,
    var interval: Int = 0) {}

 

FK를 Alarm에 둔 경우

// Item
class Item(
    var name: String, 
    var enabled: Boolean) {}

// Alarm
class Alarm(
    var filePath: String,
    var volume: Int = 100,
    var repeatTimes: Int = 20,
    var interval: Int = 0
    var item: Item? = null) {}

 

고민 끝에 다음의 이유로 Item에 Alarm을 참조하는 FK를 두기로 결정했다.

  1. Alarm은 Item과 따로 조회될 일이 없다.
  2. Item에 Alarm 변수를 두면 Item에 연결된 알람을 불러올 때마다 Alarm을 따로 조회하지 않아도 된다.

이제 각 모델에 해당하는 테이블을 만들어줘야 하는데, 이때 생성할 테이블의 Column 정보, CREATE, DROP Query를 각 Model의 클래스 안에 넣었다.

 

DBHelper의 onCreate에 넣으면 뭔가 Item, Alarm과 관련된 코드가 이곳저곳 분산되어 있는 느낌이 들기 떄문이었다.

 

완성된 Model 클래스는 다음과 같다.

 

Item.kt

class Item(var name: String, var enabled: Boolean, var alarm: Alarm? = null) {

    var id: Int = -1

    constructor(id: Int, name: String, enabled: Boolean, alarm: Alarm? = null) : this(name, enabled, alarm) {
        this.id = id
    }


    object TableInfo : BaseColumns {
        const val TABLE_NAME = "Item"
        const val COLUMN_NAME_ITEM = "Name"
        const val COLUMN_NAME_ENABLE = "IsEnabled"
        const val COLUMN_NAME_FK_ITEM_ALARM = "FK_${TABLE_NAME}_${Alarm.TableInfo.TABLE_NAME}"
    }

    companion object {
        const val SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ${TableInfo.TABLE_NAME} (" +
                "${BaseColumns._ID} INTEGER PRIMARY KEY AUTOINCREMENT," +
                "${TableInfo.COLUMN_NAME_ITEM} VARCHAR2(20) NOT NULL," +
                "${TableInfo.COLUMN_NAME_ENABLE} INTEGER NOT NULL," +
                "${TableInfo.COLUMN_NAME_FK_ITEM_ALARM} INTEGER NOT NULL," +
                "FOREIGN KEY(${TableInfo.COLUMN_NAME_FK_ITEM_ALARM}) " +
                "REFERENCES ${Alarm.TableInfo.TABLE_NAME}(${BaseColumns._ID}) " +
                "ON DELETE SET NULL)"

        const val SQL_DROP_TABLE = "DROP TABLE IF EXISTS ${TableInfo.TABLE_NAME}"
    }

    override fun toString(): String {
        return "Item(ID: $id, Name: $name, Enabled: $enabled, AlarmID: ${alarm?.id ?: "NULL"})"
    }
}

 

Alarm.kt

class Alarm(
    var filePath: String,
    var volume: Int = 100,
    var repeatTimes: Int = 20, //반복 시간(분)
    var interval: Int = 0) { //알림이 한번 종료된 후 다음 반복까지의 시간(분), 0: 계속 반복

    var id: Int = -1

    constructor(id: Int, filePath: String, volume: Int, repeatTimes: Int, interval: Int)
            : this(filePath, volume, repeatTimes, interval) {

        this.id = id
    }

    object TableInfo : BaseColumns {
        const val TABLE_NAME = "Alarm"
        const val COLUMN_NAME_FILE_PATH = "filePath"
        const val COLUMN_NAME_VOLUME = "Volume"
        const val COLUMN_NAME_REPEAT_TIMES = "RepeatTimes"
        const val COLUMN_NAME_INTERVAL = "Interval"
    }

    companion object {
        const val SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ${TableInfo.TABLE_NAME} (" +
                "${BaseColumns._ID} INTEGER PRIMARY KEY AUTOINCREMENT," +
                "${TableInfo.COLUMN_NAME_FILE_PATH} VARCHAR(50) NOT NULL," +
                "${TableInfo.COLUMN_NAME_VOLUME} INTEGER NOT NULL," +
                "${TableInfo.COLUMN_NAME_REPEAT_TIMES} INTEGER NOT NULL," +
                "${TableInfo.COLUMN_NAME_INTERVAL} INTEGER NOT NULL)"

        const val SQL_DROP_TABLE = "DROP TABLE IF EXISTS ${TableInfo.TABLE_NAME}"
    }

    override fun toString(): String {
        return "Alarm(ID: $id, FilePath: $filePath, Volume: $volume, RepeatTimes: $repeatTimes, Interval: $interval)"
    }
}

 

반응형