반응형

Room 을 사용하다보면 초기 데이터를 넣어야 하는 경우가 있을 겁니다.

 

Developer 사이트에 의하면 데이터베이스에 미리 값을 채우는 방식으로 assets 과 File system 을 사용하는 방법을 제시하고 있는데요. (참고 링크)

 

위 경우에는 Room 이 자동으로 테이블을 생성해주는 쿼리 부분을 직접 입력해줘야 합니다. 하지만 테이블 생성은 온전히 프레임워크에 맡긴채 데이터만 넣고 싶은 경우도 있는데요. 이번 포스트에서는 코드를 통해 초기 데이터를 설정하는 방법에 대해 알아보겠습니다.

 

Room 사전 준비

본문에 앞서 예제 작성을 위해 필요한 RoomDatabase 클래스와 Dao, Entity 객체에 대해 먼저 정의하도록 하겠습니다.

편의 상 한 번에 기재하지만 여러분께서는 각자 원하는 위치에 파일로 적절하게 나누면 되겠습니다.

 

@Database(
    entities = [AlbumEntity::class],
    version = 1,
    exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
    abstract fun albumDao(): AlbumDao
}

@Dao
interface AlbumDao {

    @Insert(onConflict = OnConflictStrategy.ABORT)
    suspend fun addAlbum(item: AlbumEntity)

    @Query("SELECT * FROM AlbumEntity")
    suspend fun getAllAlbums(): List<AlbumEntity>
}

@Entity
data class AlbumEntity(
    @PrimaryKey(autoGenerate = true) val id: Int,
    val name: String
) {
    companion object {
        const val DEFAULT_ALBUM_ID = 1
        val DEFAULT_ALBUM = AlbumEntity(DEFAULT_ALBUM_ID, "기본 앨범")
    }
}

 

만약 Hilt 를 사용하시는 분이라면 아래와 같이 Module 을 정의할 수 있습니다.

 

@InstallIn(SingletonComponent::class)
@Module
object DBModule {

    @Singleton
    @Provides
    fun provideAppDatabase(
        @ApplicationContext context: Context
    ): AppDatabase = Room
            .databaseBuilder(context, AppDatabase::class.java, "kim_ready.db")
            .build()

    @Singleton
    @Provides
    fun provideAlbumDao(appDatabase: AppDatabase): AlbumDao = appDatabase.albumDao()
}

 

 

RoomDatabase.Callback

위 DBModule 오브젝트의 정의를 보면, Room.databaseBuilder() 를 통해 우리가 정의한 AppDataBase 객체를 생성해주고 있는 것을 확인할 수 있는데요. 바로 여기 이 Builder 의 addCallback() 메소드를 통해서 우리는 초기 데이터 세팅을 할 수 있습니다.

 

RoomDatabase.Callback 의 정의는 아래와 같습니다.

/**
 * Callback for {@link RoomDatabase}.
 */
public abstract static class Callback {

    /**
     * Called when the database is created for the first time. This is called after all the
     * tables are created.
     *
     * @param db The database.
     */
    public void onCreate(@NonNull SupportSQLiteDatabase db) {
    }

    /**
     * Called when the database has been opened.
     *
     * @param db The database.
     */
    public void onOpen(@NonNull SupportSQLiteDatabase db) {
    }
    
    /**
     * Called after the database was destructively migrated
     *
     * @param db The database.
     */
    public void onDestructiveMigration(@NonNull SupportSQLiteDatabase db){
    }
}

 

주석을 보시면 아시겠지만, 이 콜백 클래스는 Room Database 를 생성할 때에 각각의 상황에 맞춰 콜백 함수를 전달 받고자 할 때 사용됩니다. 우리는 디비가 생성되는 시점에 초기데이터를 넣을 것이기 때문에 위 3가지 함수 중 onCrate() 함수만을 재정의할 것입니다.

 

Sample code

앞서 예제 코드를 작성할 때에는 Hilt 의 모듈에서 AppDatabase 의 인스턴스를 생성해주고 있었는데요. 우리는 이번에 AppDatabase 에서 생성되는 AppDatabase 의 DAO 객체를 통해 아이템을 insert 할 것이기 때문에 싱글톤 객체를 Hilt 에 위임하지 않고 직접 정의하는 것으로 수정하도록 하겠습니다.

 

수정된 AppDatabase  의 코드는 아래와 같습니다.

@Database(
    entities = [AlbumEntity::class],
    version = 1,
    exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
    abstract fun albumDao(): AlbumDao

    companion object {
        fun getInstance(context: Context): AppDatabase = Room
            .databaseBuilder(context, AppDatabase::class.java, "kim_ready.db")
            .addCallback(object : Callback() {
                override fun onCreate(db: SupportSQLiteDatabase) {
                    super.onCreate(db)

                    Executors.newSingleThreadExecutor().execute {
                        runBlocking {
                            getInstance(context).albumDao().addAlbum(AlbumEntity.DEFAULT_ALBUM)
                        }
                    }
                }
            })
            .build()
    }
}

 

이렇게 작성해준 다음 Hilt 의 DBModule 은 아래와 같이 수정해줍니다.

@InstallIn(SingletonComponent::class)
@Module
object DBModule {

    @Singleton
    @Provides
    fun provideAppDatabase(
        @ApplicationContext context: Context
    ): AppDatabase = AppDatabase.getInstance(context)

    @Singleton
    @Provides
    fun provideAlbumDao(appDatabase: AppDatabase): AlbumDao = appDatabase.albumDao()
}

 

이렇게 수정 했다면, 앱 실행시 최초에 디비가 생성되는 때에 우리가 정의한 DEFAULT_ALBUM 객체의 데이터가 AlbumEntity 테이블에 정상적으로 잘 셋팅 된 것을 확인할 수 있습니다.

반응형
반응형