Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm learning Android Jetpack, the following code is from a sample project at https://github.com/android/sunflower.

The GardenPlanting.kt code is to design a table, I'm very strange why the author define the table fields in two position, you see that @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") is located the inner of the class.

I think that Code B is easy to understand, right?

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
}

Code 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
}
like image 724
HelloCW Avatar asked Mar 02 '20 07:03

HelloCW


Video Answer


2 Answers

The declaration of a property inside the data class constructor is used to :

  1. Generate component function for destructing
  2. Use these fields inside the toString(), equals(), hashCode(), and copy()

So if you want to avoid copying fields with the copy method then the easy way is to declare the fields inside the body of the class.

Example:

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
}

Advantages:

  1. Create a copies of the object excluding specific fields
  2. Exclude specific fields to compare two objects with equals
  3. Exclude specific fields in destructuring declarations

Note: copy and component methods cannot be provided explicitly(inside data class). In example B, gardenPlantingId is replaced with id so can be removed.

like image 200
Pavneet_Singh Avatar answered Oct 24 '22 06:10

Pavneet_Singh


The answer is very simple:

Because in this sample code, the author wants to show that we can use both @PrimaryKey and @ColumnInfo annotation to ANY member inside an entity class, regardless its position (it can be in the inside the constructor or at the outside).

To experiment with this, you can just do exactly what you did on Code B. It is also valid, but in that case, gardenPlantingId will not have a custom column name because we don't use @ColumnInfo annotation. Also, it is not necessary to declare @PrimaryKey outside the constructor (like the given example). You can just declare your the primary key annotation inside the constructor.

like image 2
Harry Timothy Avatar answered Oct 24 '22 05:10

Harry Timothy