为什么作者用 Android Jetpack 在 Room 的两个位置定义 table 字段?

Why does the author define the table fields in two position in Room with Android Jetpack?

我正在学习 Android Jetpack,以下代码来自 https://github.com/android/sunflower.

的示例项目

GardenPlanting.kt代码是设计了一个table,我很奇怪为什么作者把table字段定义在两个位置,你看@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id")位于class.

的内部

我觉得Code B很容易理解吧?

GardenPlanting.kt

@Entity(
    tableName = "garden_plantings",
    foreignKeys = [
        ForeignKey(entity = Plant::class, parentColumns = ["id"], childColumns = ["plant_id"])
    ],
    indices = [Index("plant_id")]
)

data class GardenPlanting(
    @ColumnInfo(name = "plant_id") val plantId: String,

    @ColumnInfo(name = "plant_date") val plantDate: Calendar = Calendar.getInstance(),    

    @ColumnInfo(name = "last_watering_date")
    val lastWateringDate: Calendar = Calendar.getInstance()
) {
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "id")
        var gardenPlantingId: Long = 0
}

代码B

data class GardenPlanting(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id")  val id: String,

    @ColumnInfo(name = "plant_id") val plantId: String,

    @ColumnInfo(name = "plant_date") val plantDate: Calendar = Calendar.getInstance(),

    @ColumnInfo(name = "last_watering_date")
    val lastWateringDate: Calendar = Calendar.getInstance()
) {

        var gardenPlantingId: Long = 0
}

data class 构造函数中 属性 的声明用于:

  1. 生成component 函数用于析构
  2. toString()equals()hashCode()copy()
  3. 中使用这些字段

因此,如果您想避免使用 copy 方法复制字段,那么简单的方法是在 class.

的正文中声明字段

示例:

fun main() {
    val user = User("Pavneet", "29k+")
    user.id = kotlin.random.Random.nextInt(10, 20)
    val userCopy = user.copy()
    println(userCopy) // id won't be printed 'cuz it's not a part of toString method
    userCopy.id = 99
    print(userCopy.equals(user)) // true, 'cuz id is not being used by the equals method
    //var(name, repo, id) = userCopy // error, User must have a 'component3()' function
    var(name, repo) = userCopy

}

data class User(val name: String = "", val repo:String="0"){
    var id:Int = 0
}

优点:

  1. 创建不包括特定字段的对象的副本
  2. 排除特定字段以比较两个对象是否相等
  3. 在解构声明中排除特定字段

注意:copycomponent 方法不能明确提供(内部数据 class)。在示例 B 中,gardenPlantingId 被替换为 id,因此可以删除。

答案很简单:

因为在此示例代码中,作者想表明我们可以对实体中的 ANY 成员使用 @PrimaryKey@ColumnInfo 注释 class,不管它的位置如何(可以在构造函数内部,也可以在构造函数外部)。

要对此进行试验,您只需完全按照在 代码 B 上所做的操作即可。它也是有效的,但在那种情况下,gardenPlantingId 将没有自定义列名,因为我们不使用 @ColumnInfo 注释。此外,没有必要在构造函数外部声明 @PrimaryKey (如给定的示例)。您可以在构造函数中声明主键注释。