1. Entity 생성
: Entity 는 테이블 스키마 정의
//모든 데이터베이스는 테이블들을 가지고 있고, 그 테이블들이 어떤 컬럼들을 갖고있을지를 정의하는 게 스키마
//테이블을 만드는 쿼리문이 CREATE TABLE
// student_table이라는 이름으로 테이블을 하나 만들건데, 그 안에 student_id가 들어가고 name이 들어갈거다.
// student_id는 integer이고, primary key(유니크한, 중복되지 않는 값)를 가질거다.
// name은 text 타입인데, not null이다. null이 들어갈 수 없다.
- CREATE TABLE student_table (student_id INTEGER PRIMARY KEY, name TEXT NOT NULL);
- @Entity data class Student
@Entity(tableName = "student_table") // 테이블 이름을 student_table로 지정함
//data class를 student라는 이름으로 하나를 만드는데,
data class Student (
@PrimaryKey
//이 테이블 명이 student_table이고,
// columninfo에 name이 들어가는데 name이 "student_id"이다.
@ColumnInfo(name = "student_id")
//2개의 컬럼이 들어가게 됨, id와 name
val id: Int,
val name: String
)
2. DAO 생성
- DAO는 interface나 abstract class로 정의되어야 함
- Annotation에 SQL 쿼리를 정의하고 그 쿼리를 위한 메소드를 선언
- 가능한 annotation으로 @Insert, @Update, @Delete, @Query 가 있음
@Query("SELECT * from table") fun getAllData() : List<Data>
//테이블 안의 모든 데이터를 가져오라는 뜻
- @Insert, @Update, @Delete는 SQL 쿼리를 작성하지 않아도 컴파일러가 자동으로 생성함
- @Insert나 @Update는 key가 중복되는 경우 처리를 위해 onConflict를 지정할 수 있음
OnConflictStrategy.ABORT | key 충돌 시 종료 |
OnConflictStrategy.IGNORE | key 충돌 무시 |
OnConflictStrategy.REPLACE | key 충돌 시 새로운 데이터로 변경 |
- @Update나 @Delete는 primary key에 해당되는 튜플을 찾아서 변경/삭제함
- @Query 로 리턴되는 데이터의 타입을 LiveData<>로 하면, 나중에 이 데이터가 업데이트될 때 Observer를 통해 알 수 있음
@Query("SELECT * from table") fun getAllData() : LiveData<List<Data>>
- @Query에 SQL을 정의할 때 메소드의 인자를 사용할 수 있음
//student_table에서 모든 데이터를 갖고올건데, name이 sname인 것을 찾아줘라.
@Query("SELECT * FROM student_table WHERE name = :sname")
suspend fun getStudentByName(sname: String): List<Student>
// 인자 sname을 SQL에서 :sname으로 사용
- fun 앞에 suspend는 Kotlin coroutine을 사용하는 것... 나중에 이 메소드를 부를 때에는 runBlocking { } 안에서 호출해야 함
- LiveData는 비동기적으로 동작하기 때문에 coroutine으로 할 필요가 없음
@Dao
interface MyDAO {
@Insert(onConflict = OnConflictStrategy.REPLACE) // INSERT, key 충돌이 나면 새 데이터로 교체
suspend fun insertStudent(student: Student)
@Query("SELECT * FROM student_table")
fun getAllStudents(): LiveData<List<Student>> // LiveData<> 사용
@Query("SELECT * FROM student_table WHERE name = :sname")
suspend fun getStudentByName(sname: String): List<Student>
@Delete
suspend fun deleteStudent(student: Student); // primary key is used to find the student
// ...
}
- @Query("SELECT * from table") fun getAllData() : LiveData<List<Data>>
@Query("SELECT * FROM student_table WHERE name = :sname")
suspend fun getStudentByName(sname: String): List<Student>
- 인자 sname을 SQL에서 :sname으로 사용
3. Database 생성
- RoomDatabase를 상속해 자신의 Room 클래스를 만들어야 함
- 포함되는 Entity들과 데이터베이스 버전(version)을 @Database annotation에 지정함
- version이 기존에 저장되어 있는 데이터베이스보다 높으면, 데이터베이스를 open할 때 migration을 수행하게 됨
- Migration 수행 방법은 RoomDatabase 객체의 addMigration() 메소드를 통해 알려줌
//Migration을 통해 기존에 깔려있던 앱에 테이블을 추가...
- DAO를 가져올 수 있는 getter 메소드를 만든다
- 실제 메소드 정의는 자동으로 생성됨
- Room 클래스의 인스턴스는 하나만 있으면 되니까 Singleton 패턴을 사용함
- Room 클래스의 객체 생성은 Room.databaseBuilder() 를 이용
@Database(entities = [Student::class, ClassInfo::class, Enrollment::class, Teacher::class], version = 1)
abstract class MyDatabase : RoomDatabase() {
abstract fun getMyDao() : MyDAO
companion object {
private var INSTANCE: MyDatabase? = null
private val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) { 생략 }
}
private val MIGRATION_2_3 = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) { 생략 }
}
fun getDatabase(context: Context) : MyDatabase {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
context, MyDatabase::class.java, "school_database")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3)
.build()
}
return INSTANCE as MyDatabase
}
}
}
4. Migration
- 앞에서 MyRoomDatabae 객체 생성 후 addMigrations() 메소드를 호출해 Migration 방법을 지정했음
- 여러개의 Migration 지정 가능
//Migration을 통해 기존에 깔려있던 앱에 테이블을 추가...
Room.databaseBuilder(...).addMigrations(MIGRATION_1_2, MIGRATION_2_3)
private val MIGRATION_1_2 = object : Migration(1, 2) { // version 1 -> 2
override fun migrate(database: SupportSQLiteDatabase) {
//ALTER : 테이블을 변경하는 것
// ADD COLUMN : 컬럼을 하나? 추가한다
database.execSQL("ALTER TABLE student_table ADD COLUMN last_update INTEGER")
}
}
private val MIGRATION_2_3 = object : Migration(2, 3) { // version 2 -> 3
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE class_table ADD COLUMN last_update INTEGER")
}
}
'Android Studio' 카테고리의 다른 글
[Android 앱개발 심화] 위치 정보 활용 (2) - 구글 지도앱 만들기 (코드) (@@ 내용들 다 수정하기) (0) | 2024.05.01 |
---|---|
[Android 앱개발 심화] 데이터 저장(2) - Room (개요, 3요소, gradle) (# ) (0) | 2024.04.30 |
[Android 앱개발 심화] 데이터 저장 (1) - SharedPreferences (# 추가하기) (0) | 2024.04.30 |
[Android 앱개발 숙련] 알림 - 예제, 권한 (# 확인...?) (0) | 2024.04.12 |
[Android 앱개발 숙련] 알림 - 개념 (# 주석확인) (0) | 2024.04.12 |