【问题标题】:Purpose of overriding hashcode for an Entity classs覆盖实体类的哈希码的目的
【发布时间】:2023-01-12 05:42:31
【问题描述】:

我只需要澄清一下,但这是我们覆盖 hashcode 方法的原因,为存储在 database 中的每个 instance 提供一个唯一地址。如果是这样,为什么不自动生成 hashcode?

我还有另一个关于Room Databases 的问题,我知道有些文章(来自新闻 API)没有 ID,因此我必须找到一种方法来识别文章,因为 Room 需要 ID。

我尝试将 URL 设置为 Primary Key 但是我收到此错误 error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such column: id) public abstract androidx.lifecycle.LiveData<java.util.List<com.example.secondnews.Article>> getAllArticles();

然后我添加了一个 ID 参数,点击后导致崩溃这是错误 java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference

在询问之后,我得到了这个解决问题的答案,但是我无法解决这个问题,为什么我们要检查if(url.isNullOrEmpty())?我认为 Url 永远不会为空,因此这行代码永远不会运行 result = 31 * result + url.hashCode()

 override fun hashCode(): Int {
        var result = id.hashCode()
        if(url.isNullOrEmpty()){
            result = 31 * result + url.hashCode()
        }
        return result
    }

如果ID 为空,var result = id.hashCode() 不会返回零吗?因为URL 永远不会为空,这意味着我们将返回零作为哈希码?

此外,设置 @PrimaryKey(autoGenerate = true) 不会导致自动生成 ID 吗?如果是这样的话,ID 怎么会是空的?

房间实体

@Entity(
    tableName = "articles", indices = [Index(value = ["url","title"], unique = true)]
    )

@Parcelize
data class Article(
    @PrimaryKey(autoGenerate = true)
    var id: Int? =null,
    val author: String?,
    val description: String?,
    val source: Source?,
    val title: String?,
    val url: String?,
    val urlToImage: String?,
    val publishedAt: String?,
    val content: String?
): Parcelable {
    override fun hashCode(): Int {
        var result = id.hashCode()
        if(url.isNullOrEmpty()){
            result = 31 * result + url.hashCode()
        }
        return result
    }

}

【问题讨论】:

    标签: android android-room


    【解决方案1】:

    当 autoGenerate = true 被编码或什至没有被编码并且只使用具有可为空整数类型的 @PrimaryKey 时,列的值由 SQLite NOT ROOM 生成,因此在插入行之前是未知的。

    源对象不会更改,但方便 @Insert 可以处理作为 Long 返回的值。

    以,例如

    @Dao
    interface TheDAO {
        @Insert
        fun insert(article: Article): Long
    }
    

    你可以做类似的事情

    var myArticle = Article(author = "Fred", .....)
    myAricle.id = dao.insert(myArticle).toInt()
    
    • 其中dao已被适当地获取(实例化)

    自动生成

    正如上面所推断的那样,决定自动生成值的不是 autoGenerate 是否为真。事实上,ROOM 表的潜在价值总是生成的(即 SQLite 确实适合 WITHOUT ROWID 表,ROOM 在撰写本文时不支持它们的使用)。

    更具体地说,对于没有 WITHOUT ROWID 的表,总是有一个名为的隐藏列行号这是一个由 SQLite 生成的整数值,它将比表中的最高 rowid 大 1(或者应该达到最高可能值然后是未使用的值)。

    如果列类型是 INTEGER(Room 使用 INTEGER 类型表示 Int、Long、Byte、Boolean ....)并且该列是 PRIMARY KEY(又名 @PrimaryKey 注释),那么该列是行号柱子。如果未指定该值,则将生成 rowid(比表中的最高 rowid 大 1 或 1),因为该列是 rowid 的别名,它也将具有此值。

    autoGenerate = true 所做的是在列类型为 INTEGER 时添加 SQLite AUTOINCREMENT 关键字。

    这添加了一个约束/规则,表明生成的数字必须更大并且曾经使用过(不删除具有最高 rowid 的行将允许重新使用该 rowid)。

    为了便于记录曾经使用过的最高值,系统表 sqlite_sequence 用于存储每个表的最高值。维护这样的表会产生开销。SQLite 文档指出:-

    • AUTOINCREMENT 关键字强加了额外的 CPU、内存、磁盘空间和磁盘 I/O 开销,如果不是严格需要,应该避免使用。通常不需要。

    不妨参考https://www.sqlite.org/autoinc.html

    【讨论】:

      猜你喜欢
      • 2014-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-21
      • 1970-01-01
      • 2017-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多