Android——Room筆記

Room是官方基於SQLite數據庫封裝的庫。以前我們都是用的第三方orm,或者自己寫的。

首先引入

def room_version = "2.2.3"

implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor

Room有3個組件:

1、Database: Contains the database holder and serves as the main access point for the underlying connection to your app's persisted, relational data.

The class that's annotated with @Database should satisfy the following conditions:

    1、Be an abstract class that extends RoomDatabase.
    2、Include the list of entities associated with the database within the annotation.
    3、Contain an abstract method that has 0 arguments and returns the class that is annotated with @Dao.
At runtime, you can acquire an instance of Database by calling Room.databaseBuilder() or Room.inMemoryDatabaseBuilder().

2、Entity: Represents a table within the database.

3、DAO: Contains the methods used for accessing the database.

1、DataBase:單例,創建數據庫管理類,包含Dao實例

2、Dao:提供數據庫操作方法

3、Entity:描述一個表的屬性字段

一、DataBase

@Database(entities = arrayOf(User::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

// 創建數據庫
val db = Room.databaseBuilder(applicationContext, AppDatabase::class.java, "database-name").build()

1.1、Use type converters:類型轉換

有些我們常用的類型不能在數據庫中保存,這時候我們需要將其轉換成數據庫能保存的類型。

以下的Date在Database中會被Converters轉換成Long類型數據再保存到數據庫

class Converters {
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }

    @TypeConverter
    fun dateToTimestamp(date: Date?): Long? {
        return date?.time?.toLong()
    }
}

@Database(entities = arrayOf(User::class), version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

@Entity
data class User(private var birthday: Date?)

@Dao
interface UserDao {
    @Query("SELECT * FROM user WHERE birthday BETWEEN :from AND :to")
    fun findUsersBornBetweenDates(from: Date, to: Date): List<User>
}

二、Dao

@Dao
interface UserDao {
    @Query("SELECT * FROM user")
    fun getAll(): List<User>

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    fun loadAllByIds(userIds: IntArray): List<User>

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
           "last_name LIKE :last LIMIT 1")
    fun findByName(first: String, last: String): User

    @Insert(onConflict = REPLACE)
    fun insertAll(vararg users: User)

    @Delete
    fun delete(user: User)
}

@Insert(onConflict = REPLACE):新增數據時如果有衝突就替換舊的。

三、Entity

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

@Entity:表示註冊一個table,表名爲類名

@PrimaryKey:每個@Entity都必須有一個@PrimaryKey

這裏的字段默認是public的,如果設置爲private,則需要提供setter和getter

3.1、使用PrimaryKey

@Entity(primaryKeys = arrayOf("firstName", "lastName"))
data class User(
    @PrimaryKey var id,
    var firstName: String?,
    var lastName: String?
)

每個表必須定義PrimaryKey,如果只有一個可以使用@PrimaryKey定義,如果有多個,則需要使用primaryKeys=arrayOf()定義,primaryKeys是@Entity的屬性,當然@Entity還有其他屬性,接下來會慢慢說明。

3.2、定義表名

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

表名默認爲類名,如果需要表名跟類名不同,可以使用@Entity的屬性tableName來設置

3.3、定義表字段

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

@ColumnInfo:可選,重定義Table的字段名,默認使用屬性名作爲字段名,如果需要字段名跟屬性名不同,可以如此設置。

3.4、Ignore fields:忽略屬性

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

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

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

@Ignore:有時候我們不需要將類的所有屬性都保存到數據庫,這時候就需要添加@Ignore來忽略這些屬性了。

3.5、Index specific columns:索引

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

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

indices:可以創建索引以加快查詢速度。

unique:唯一性,有時候除了primaryKey之外其他字段的值也可能是需要唯一的,免得存在重複數據,比如身份證號等。

3.6、Define relationships between objects:外鍵

@Entity(foreignKeys = arrayOf(ForeignKey(
            entity = User::class,
            parentColumns = arrayOf("id"),
            childColumns = arrayOf("user_id"),
            onDelete = CASCADE, onUpdate = CASCADE)
       )
)
data class Book(
    @PrimaryKey var bookId: Int,
    var title: String?,
    @ColumnInfo(name = "user_id") var userId: Int
)

foreignKeys:Room是禁止Entity包含Entity的。只能使用foreignKeys設置。

CASCADE:表示關聯刪除/更新

3.7、Create nested objects:定義非Entity屬性

data class Address(
    var street: String?,
    var state: String?,
    var city: String?,
    @ColumnInfo(name = "post_code") var postCode: Int
)

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

@Embedded:可添加非Entity類屬性,Entity表中不會出現非Entity類字段,而是將非Entity類的屬性作爲Entity表的字段。

參考以上代碼,User表的字段爲:id, firstName, street, state, city, post_code

四、DatabaseView

@DatabaseView("SELECT user.id, user.name, user.departmentId," +
        "department.name AS departmentName FROM user " +
        "INNER JOIN department ON user.departmentId = department.id")
data class UserDetail(
    var id: Long,
    var name: String?,
    var departmentId: Long,
    var departmentName: String?
)

@Database(entities = arrayOf(User::class),
          views = arrayOf(UserDetail::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

註冊DatabaseView

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章