[ 안드로이드 ] 제목
DAO
DAO는 인터페이스(interface)나 추상 클래스(abstract)로 정의할 수 있다. 안드로이드 공식 문서에 따르면 일반적으로는 인터페이스로 사용하라고 권장하고 있다.
DAO 인터페이스 (또는 추상 클래스)에는 무조건 @Dao 어노테이션을 선언해주어야 한다. Retrofit의 Service와 매우 유사하기 때문에 많이 익숙한 형태이다.
@Dao
interface MedicineDao {
@Insert
fun insert(medicine: Medicine)
@Insert
fun insertAll(medicines: List<Medicine>)
@Update
fun update(medicine: Medicine)
@Delete
fun delete(medicine: Medicine)
@Query("DELETE FROM medicine WHERE id = :id")
fun deleteById(id: Int)
@Query("DELETE FROM medicine WHERE itemCode = :itemCode")
fun deleteByItemCode(itemCode: String)
@Query("SELECT * FROM medicine")
fun findAll(): List<Medicine>
}
데이터베이스 동작을 정의하는 Dao의 메서드에는 두 가지 유형이 있다.
- 편의 메서드 : SQL 코드 작성 없이 CRUD를 가능하게 해준다. 위의 코드에서 @Insert, @Update, @Delete 등이 해당된다.
- 쿼리 메서드 : 사용자가 직접 SQL 쿼리를 작성할 수 있다.
편의 메서드
편의 메서드는 위에서 말했듯이, 개발자가 SQL 문을 작성하지 않아도 CRUD가 가능하다. 물론, 복잡한 동작을 하기 위해선 쿼리 메서드를 사용해야 한다.
삽입 (@Insert)
@Insert를 통해 매개변수로 전달 받은 변수를 데이터베이스에 삽입할 수 있다.
@Dao
interface MedicineDao {
@Insert
fun insert(medicine: Medicine)
@Insert
fun insertAll(medicines: List<Medicine>)
}
@Insert 메서드는 long 타입으로 삽입된 항목의 의 rowId를 반환한다. 만약, 배열이나 컬렉션이면 메서드는 long 값의 배열이나 컬력션을 반환해야 하며, 각 값은 삽입된 항목의 rowId를 나타낸다.
자세한 내용 : rowId 테이블 SQLite 문서
❗ 주의할 점 ❗
@Insert 메서드의 매개변수는 @Entity 어노테이션이 선언된 Room 데이터 항목 클래스(Entity) 이거나, 데이터 항목 클래스 인스턴스의 컬렉션이어야 한다.
즉, Entity 클래스와 Entity 클래스의 컬렉션 (List 등)만 가능하다는 뜻이다.
수정 (@Update)
@Update는 기본 키(Primary Key)를 사용하여 전달된 항목 인스턴스를 데이터베이스의 행과 일치시킨다. 기본 키가 같은 행이 없으면 Room에서는 아무것도 변경하지 않는다.
@Insert와 마찬가지로 Room 데이터 항목 인스턴스(Entity)를 매개변수로 받을 수 있다.
@Dao
interface MedicineDao {
@Update
fun update(medicine: Medicine)
}
@Update는 성공적으로 업데이트 된 행의 수 (Int)를 반환할 수 있다.
삭제 (@Delete)
@Delete는 특정 행을 삭제한다. 사용법은 위의 삽입, 수정과 동일하며, 성공적으로 삭제된 행 수를 나타내는 Int 값을 반환할 수 있다.
@Dao
interface MedicineDao {
@Delete
fun delete(medicine: Medicine)
}
쿼리 메서드
@Query 어노테이션을 통해서 SQL문을 직접 작성할 수 있다.
Room은 컴파일 타임에 SQL 쿼리를 검증한다. 만약 SQL 쿼리에 문제가 있으면 런타임 때 오류가 나는 것이 아닌 컴파일 오류가 발생한다.
Room의 가장 큰 장점인 것 같다.
@Dao
interface MedicineDao {
@Query("DELETE FROM medicine WHERE id = :id")
fun deleteById(id: Int)
@Query("DELETE FROM medicine WHERE itemCode = :itemCode")
fun deleteByItemCode(itemCode: String)
@Query("SELECT * FROM medicine")
fun findAll(): List<Medicine>
}
특정 열만 추출하기
데이터베이스를 사용하다보면 꼭 튜플의 전체를 가져올 필요가 없는 경우가 많다.
안드로이드에서 Room을 사용할 때도 동일한데, UI에 보여주는 데이터는 1~2개인데 튜플 전체를 가져올 필요가 없는 것이다.
리소스를 절약하고 쿼리 실행을 간소화하려면 필요한 필드만 쿼리하는 것을 권장하고 있다.
Room에서 특정 열만 추출하는 것은 간단하다.
아래와 같이 필요한 필드만 선언된 data class를 생성한다.
data class NameTuple(
@ColumnInfo(name = "first_name") val firstName: String?,
@ColumnInfo(name = "last_name") val lastName: String?
)
그 후, 쿼리 메서드를 작성해주기만 하면 된다.
@Query("SELECT first_name, last_name FROM user")
fun loadFullName(): List<NameTuple>
이렇게하면 Room이 알아서 데이터를 매핑해준다. 만약 쿼리가 반환된 객체의 필드에 매핑되지 않는 열을 반환할 경우 Room이 경고를 표시해준다.
쿼리에 매개변수 전달
쿼리에 매개변수를 전달할 수 있다. Spring Boot의 JPA를 사용해봤다면 매우 익숙한 형태일 것이다.
아래와 같이 메서드의 매개변수의 이름 앞에 :(콜론)을 붙여주면 된다.
@Query("SELECT * FROM user WHERE age > :minAge")
fun loadAllUsersOlderThan(minAge: Int): Array<User>
아래와 같이 여러번 참조할 수도 있다.
@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
fun loadAllUsersBetweenAges(minAge: Int, maxAge: Int): Array<User>
@Query("SELECT * FROM user WHERE first_name LIKE :search " +
"OR last_name LIKE :search")
fun findUserWithName(search: String): List<User>
쿼리에 매개변수 컬렉션(배열, 리스트) 전달
매개변수로 컬렉션을 전달해야하는 경우가 있을 수 있다. 아래와 같이 컬렉션도 쿼리문에서 사용할 수 있다.
@Query("SELECT * FROM user WHERE region IN (:regions)")
fun loadUsersFromRegions(regions: List<String>): List<User>
멀티 매핑 반환
Room 2.4 이상에선 추가적인 데이터 클래스를 작성하지 않고도 여러 테이블의 열을 가져올 수 있다.
자세한 내용 : 멀티 매핑 반환
@Query(
"SELECT * FROM user" +
"JOIN book ON user.id = book.user_id"
)
fun loadUserAndBookNames(): Map<User, List<Book>>
Paging 라이브러리를 사용하여 페이지로 나눈 쿼리
Room은 Paging 라이브러리와의 통합을 통해 페이지로 나눈 쿼리를 지원한다. Room 2.3.0-alpha01 이상에서 DAO는 Paging 3과 함께 사용할 PagingSource 객체를 반환할 수 있다.
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE label LIKE :query")
fun pagingSource(query: String): PagingSource<Int, User>
}
'안드로이드 > 이론' 카테고리의 다른 글
[ 안드로이드 ] Retrofit2를 이용하여 서버와 통신하기 (2) - 예시 (0) | 2023.05.04 |
---|---|
[ 안드로이드 ] Retrofit2를 이용하여 서버와 통신하기 (1) - 안전하게 통신하기 (SafeApiCall) (0) | 2023.05.04 |
[ 안드로이드 ] RecylcerView + Filterable을 이용하여 실시간 검색 기능 구현하기 (0) | 2023.04.07 |
[ 안드로이드 ] BottomSheetDialog 테두리 둥글게 설정하기 (0) | 2023.04.04 |
[ 안드로이드 ] - Selector를 이용하여 버튼, 체크박스 등에 클릭 효과 주기 (0) | 2023.03.29 |