본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[android] Define data using entities - Room 에 대해 알아보자

by 돼지왕 왕돼지 2020. 8. 19.
반응형

 

android room define entities

 

-

Room 을 사용할 때 entity 들을 정의하게 된다.

각각의 entity 는 Database 의 table 에 매칭된다.

Database class 에 entities array 로 제공하면 자동으로 생성된다.

 

 

-

@Entity
data class User(@PrimaryKey var id:Int, var firstName:String?, var lastName:String?)

 

 

-

field 를 public 으로 만들거나, getter, setter 를 제공해주면 된다.

getter, setter 를 사용할 경우, JavaBeans convention 을 따른다는 것을 알고 써야 한다.

 

 

-

Entity 는 empty constructor 를 가질 수도 있고, entity 의 field 들을 가질 수도 있다.

또한 full, partial constructor 도 가질 수 있다. (partial 은 일부 field 만 가지고 있는 경우)

 

 

 

Use a primary key

 

-

각각의 entity 는 적어도 한개의 primary key 를 정의해야 한다.

한개의 field 만 있다고 해도, 그 녀석을 @PrimaryKey annotate 해야 한다.

automatic ID 를 지정하고 싶다면, @PrimaryKey 에 autoGenerate property 를 지정하면 된다.

composite primary key 를 가져야 한다면, @Entity 에 primaryKeys property 를 지정하면 된다.

@Entity(primaryKeys = arrayof("firstName", "lastName"))
data class User(
    val firstName:String?
    val lastName:String?
)

 

 

-

기본적으로 Room 은 database table name 으로 class name 을 그대로 사용한다.

만약 table 이 이름을 다르게 가져갔으면 한다면, @Entity 에 tableName property 를 지정해주면 된다.

@Entity(tableName = "users")
data class User( 
    // …
)

 

 

-

참고로 SQLite 의 table name 은 case-insensitive 하다.

 

 

-

Room 은 field name 을 column name 으로 사용한다.

만약 다른 이름을 사용하게 하고 싶다면, @ColumnInfo annotation 을 field 에 사용해주면 된다.

@Entity(tableName = "users")
data class User(
    @PrimaryKey val id:Int,
    @ColumnInfo(name = "first_name") val firstName:String?,
    @ColumnInfo(name = "last_name") val lastName:String?
)

 

 

 

 

 

 

 

Ignore fields

 

-

기본적으로 Room 은 entity 에 정의된 모든 field 에 대해 column 을 생성한다.

만약 entity 가 가진 field 중에 column 으로 만들고 싶지 않은 것이 있다면, @Ignore annotation 을 넣어주면 된다.

@Entity
data class User(
    @PrimaryKey val id:Int,
    val firstName:String?,
    val lastName:String?,
    @Ignore val picture:Bitmap?
)

 

 

-

entity 가 parent entity 를 가질 경우, @Entity 의 ignoreColumns property 를 사용하는 것이 더 쉽다.

open class User{
    var picture:Bitmap? = null
}

@Entity(ignoreColumns = arrayOf("picture"))
data class RemoteUser(
    @PrimaryKey val id:Int,
    val hasVpn:Boolean
): User()

 

 

 

Provide table search support

 

-

Room 은 annotation 을 통해 db table 의 상세정보를 검색할 수 있는 쉬운 방법을 제공한다.

app 의 minSdkVersion 이 16(JB) 이상이면, full-text search 를 할 수 있다.

 

 

* Support full-text search

 

-

앱이 db 안의 정보를 full-text search(FTS) 를 통해 빠르게 접근하고자 한다면, entity 들이 FTS3, FTS4 SQLite extension module 을 사용하는 virtual table 을 갖도록 하면 된다.

이 기능을 사용하기 위해서는 Room 2.1.0 이상이어야 하며, @Fts3 또는 @Fts4 annotation 을 해당 entity 에 주면 된다.

// 오래된 SQLite version 과 호환되기 위해서나, disk 용량이 적다면 Fts3 을 쓰는 것이 좋다.
@Fts4
@Entity(tableName = "users")
data class User(
    // FTS-table-backed entity 를 위해 primary key 를 지정하는 것은 optional 이다. 그러나 지정한다면, 이 type 과 column name 을 사용해야 한다.
    @PrimaryKey @ColumnInfo(name = "rowId") val id:Int,
    @ColumnInfo(name = "first_name") val firstName:String?
)

 

 

-

FTS-enabled table 은 항상 primary key 를 INTEGER type 으로 사용한다. 그리고 그 이름은 rowId 가 된다.

FTS-table-backed entity 가 primary key 를 정의한다면, 반드시 해당 type 과 column name 을 써야 한다.

 

 

-

table 이 여러개의 언어를 지원한다면, languageId option 을 column 에 주어서 각각의 row 에 언어 정보를 넣을 수 있다.

@Fts4(languageId = "lid")
@Entity(tableName = "users")
data class User(
    @ColumnInfo(name = "lid") val languageId:Int
)

 

 

-

Room 은 FTS-backed entity 정의를 위한 다른 option 들도 제공한다. result ordering, tokenizer type, 외부 컨텐츠로 관리되는 table 들이 그 예이다.

 

 

-

돼왕 참고사항 (https://developer.android.com/reference/androidx/room/Fts3)

 

FTS3 와 FTS4 는 SQLIte virtual table module 로, 문서들에서 full-text search 를 할 수 있도록 도와준다.

FTS entity table 은 항상 rowid 라는 이름의 column 을 가져야 하며, 이 녀석은 INTEGER PRIMARY KEY 이며 index 이다.

다시 말해 FTS entity 는 PrimaryKey 로 annotate 된 하나의 필드만 가질 수 있으며, 이것의 이름은 rowid 여야 하고, INTEGER 타입이어야 한다.

해당 필드는 클래스에서 생략될 수 있지만, 그래도 query 에서는 계속 사용된다.

 

FTS entity 의 rowid 를 제외한 모든 필드는 TEXT type 이다.

 

 

* Index specific columns

 

-

앱이 FTS3 이나 FTS4-table-backed entity 를 사용하는 것을 지원하지 않는 SDK version 을 지원해야 한다면, query 속도 향상을 위해 index 를 사용할 수 있다.

entity 에 index 를 추가하기 위해서는 @Entity 에 indices property 를 통해 index 또는 composite index 로 만들고 싶은 column name 을 전달해주면 된다.

@Entity(indices = arrayOf(Index(value = ["last_name", "address"])))
data class User(
    @PrimaryKey val id: Int,
    val firstName:String?,
    val address:String?,
    @ColumnInfo(name = "last_name") val lastName:String?,
    @Ignore val picture:Bitmap?
)

 

 

-

종종 몇몇 field 또는 field group 은 db 에서 unique 해야만 한다.

이 unique 성을 @Index annotation 의 unique property 를 true 로 줌으로써 구현할 수 있다.

@Entity(indices = arrayOf(Index(value = ["first_name", "last_name"], unique = true)))
data class User(
    @PrimaryKey val id:Int,
    @ColumnInfo(name = "first_name") val firstName:String?,
    @ColumnInfo(name = "last_name") val lastName:String?,
    @Ignore var picture:Bitmap?
)

 

 

 

 

 

 

 

Include AutoValue-based objects

 

-

이 기능은 Java-based entity 에서만 사용할 수 있는 기능이다.

이 기능을 kotlin 기반에서 똑같이 구현하려면 data class 를 쓰는 것이 좋다.

 

 

-

Room 2.1.0 이상에서 Java-based immutable value class 를 만들 수 있으며, 이는 @AutoValue 라는 annotation 을 사용하면 된다.

이 기능은 2개의 entity instance 들의 column 들이 같은 값을 가지고 있을 때, 해당 entity 들이 같은 녀석이라고 판단할 때 좋다.

 

 

-

@AutoValue 로 annotate 된 class 들을 사용할 때, @PrimaryKey, @ColumnInfo, @Embedded, @Relation 등을 이용하여 class 의 abstract method 들을 annotate 해야 한다.

이 annotation 들을 사용할 때 반드시 @CopyAnnotations 을 매번 지정해서, Room 이 auto-generated implementation 을 제대로 해석할 수 있게 도와줘야 한다.

@AutoValue
@Entity
public abstract class User{
    @CopyAnnotations // 이 녀석을 안 써주면, auto-generated 된 table 에서 @PrimaryKey 정보가 사라진다.
    @PrimaryKey
    public abstract long getId();

    public abstract String getFirstName();
    public abstract String getLastName();

    // Room 이 User object 를 만들기 위해서 factory method 를 사용한다.
    public static User create(long id, String firstName, String lastName){
        return new AutoValue_User(id, firstName, lastName);
    }
}

 

 

-

돼왕 참고사항

@AutoValue 가 자동으로 hashCode(), equals(), toString() 함수를 만들어준다.

자동으로 생성된 class 이름은 AutoValue_OriginalClassName 이 된다.

그러나 외부에서 사용하는 이름은 OriginalClassName 그대로 사용하면 된다.

 

 

-

참고자료

https://developer.android.com/training/data-storage/room/defining-data

 

 

 

반응형

댓글