【问题标题】:How to make primary key as autoincrement for Room Persistence lib如何使主键作为房间持久性库的自动增量
【发布时间】:2017-10-21 22:11:18
【问题描述】:

我正在创建一个实体 (Room Persistence Library) 类 Food,我想将 foodId 设为自动增量。

@Entity
class Food(var foodName: String, var foodDesc: String, var protein: Double, var carbs: Double, var fat: Double)
{
    @PrimaryKey
    var foodId: Int = 0
    var calories: Double = 0.toDouble()
}

如何将foodId 设置为自增字段?

【问题讨论】:

  • 你可以使用 0.0 而不是 0.toDouble() 将其声明为双精度
  • 如何创建 Food 类的新实例?您是手动指定 ID 还是将其留空?
  • 给未来读者的注意事项 - Room 的主键必须为 0 才能将其视为未设置。如果您使用任何其他默认值(例如 -1),Room 将不会自动生成 id。

标签: android kotlin android-room


【解决方案1】:

在这么多答案之后,这令人难以置信,但最后我的做法并没有什么不同。我不喜欢主键可以为空,我想把它作为第一个参数,也想插入而不定义它,它也不应该是 var。

@Entity(tableName = "employments")
data class Employment(
    @PrimaryKey(autoGenerate = true) val id: Long,
    @ColumnInfo(name = "code") val code: String,
    @ColumnInfo(name = "title") val name: String
){
    constructor(code: String, name: String) : this(0, code, name)
}

【讨论】:

  • 现在,您如何在不传递 id 作为参数的情况下调用此类 Employee?请告诉。
  • @JaiminModi 你在那里看到二级构造函数吗?你可以称之为就业(代码=“代码”,名称=“名称”)或简单的就业(“代码”,“名称”)
  • 在这种情况下甚至不需要创建额外的构造函数。只需将 0 作为默认参数添加到 id 中,您就可以自动使用构造函数,而无需额外声明:@PrimaryKey(autoGenerate = true) val id: Long = 0L,
  • 如果您添加默认值作为第一个参数,您将自动能够在没有此额外声明的情况下使用构造函数,这不是真的。在这种情况下,您将不得不使用命名参数,这在我的情况下大多是不可取的,所以这就是这里需要辅助构造函数的原因。
  • 我的意思是,在构造一个需要这么多字符串、整数和长整数作为参数的类时使用命名参数可能是更好的方法。
【解决方案2】:

使用下面的代码注释您的实体类。

在 Java 中:

@PrimaryKey(autoGenerate = true)
private int id;

在 Kotlin 中:

@PrimaryKey(autoGenerate = true)
var id: Int

Room 会自动生成并自动增加 id 字段。

【讨论】:

    【解决方案3】:

    这对我有用:

    @Entity(tableName = "note_table")
    data class Note(
        @ColumnInfo(name="title") var title: String,
        @ColumnInfo(name="description") var description: String = "",
        @ColumnInfo(name="priority") var priority: Int,
        @PrimaryKey(autoGenerate = true) var id: Int = 0//last so that we don't have to pass an ID value or named arguments
    )
    

    请注意,在将实体插入到 Room 之前,id 是最后一个,以避免在创建实体时必须使用命名参数。将其添加到房间后,在更新实体时使用 id。

    【讨论】:

      【解决方案4】:

      添加@PrimaryKey(autoGenerate = true)

      @Entity
      public class User {
      
          @PrimaryKey(autoGenerate = true)
          private int id;
      
          @ColumnInfo(name = "full_name")
          private String name;
      
          @ColumnInfo(name = "phone")
          private String phone;
      
          public User(){
          }
      
          //type-1
          public User(String name, String phone) {
              this.name = name;
              this.phone = phone;
          }
      
          //type-2
          public User(int id, String name, String phone) {
              this.id = id;
              this.name = name;
              this.phone = phone;
          }
      
      }
      

      同时存储数据

       //type-1
       db.userDao().InsertAll(new User(sName,sPhone)); 
      
       //type-2
       db.userDao().InsertAll(new User(0,sName,sPhone)); 
      

      类型 1

      如果您没有为主键传递值,默认情况下它将为 0 或 空。

      类型 2

      在创建对象(我的案例用户对象)时为 id 设置 null 或零

      如果字段类型是 long 或 int(或其 TypeConverter 将其转换为 long 或 int),则 Insert 方法在插入项目时将 0 视为未设置。

      如果字段的类型是 Integer 或 Long (Object)(或其 TypeConverter 将其转换为 Integer 或 Long),则 Insert 方法在插入项目时将 null 视为未设置。

      【讨论】:

      • 我们能否将自定义 id 传递给实体,即使它设置为自动生成?
      • @Igor Ganapolsky 是的,但是条目将使用该自定义 id 生成 [自动增量将不起作用] 如果您再次传递相同的 id,它将抛出异常“唯一约束失败”,因此您需要始终通过新 id 或设为 [0 或 null] 并让自动增量为您完成这项工作。
      • 如果您想自动生成,为什么还要让用户将 id 放入构造函数中?
      • 在 Kotlin 中,您可以使用数据类并编写:val jack = User(name = "Jack", phone= 1) 在这种情况下,您可以从构造函数中删除 0
      • @hellcast 如果你没有在构造函数中包含 id (正如我刚刚学到的艰难方法),当你查询数据库时,它不会分配 id 字段(它只是你在构造函数中初始化它),因为我假设它在填充对象的字段时调用相同的构造函数。
      【解决方案5】:

      您需要使用autoGenerate 属性

      你的主键注释应该是这样的:

      @PrimaryKey(autoGenerate = true)
      

      PrimaryKey 的参考。

      【讨论】:

      • 谢谢,我在找autoIncrement,所以没找到。
      • 嘿@MatPag 如果我想要一个表中的两个主键(复合主键)并且主键之一应该自动递增怎么办?我怎样才能做到这一点?你能回答这个here 吗?
      • @MatPeg 如果我想要一个 PrimaryKey 是自己生成的,而另一个来自 REST @Entity( primaryKeys = arrayOf(COLUMN_ID_LOCAL,COLUMN_ID_REMOTE)) 怎么办?
      • @murt 你需要一个复合主键,但你不能做你想做的事。阅读here
      • 链接文档的重要部分:Insert methods treat 0 as not-set while inserting the item.
      【解决方案6】:

      例如,如果您想要存储一个 users 实体,其中包含字段 (firstname, lastname , email) 并且您想要自动生成的 id,那么您可以这样做。

      @Entity(tableName = "users")
      data class Users(
         @PrimaryKey(autoGenerate = true)
         val id: Long,
         val firstname: String,
         val lastname: String,
         val email: String
      )
      

      Room 将自动生成并自动增加 id 字段。

      【讨论】:

      • 每次我们创建一个新的 Users 对象时,我们都需要传递一个 id 字段。这可以避免吗?
      • 是的,把@PrimaryKey(autoGenerated = true) val id: Long? = null放在构造函数之外,放在类的主体上
      • @Magritte Care 请详细说明?
      • @Ispam 在我上面的回答中,我发布了完整类的外观。
      • 其实你可以简单的把0作为ID。如果你设置了@PrimaryKey 选项,房间会自动生成一个ID。
      【解决方案7】:
      @Entity(tableName = "user")
      data class User(
      
      @PrimaryKey(autoGenerate = true)  var id: Int?,
             var name: String,
             var dob: String,
             var address: String,
             var gender: String
      )
      {
          constructor():this(null,
              "","","","")
      }
      

      【讨论】:

      • 虽然此代码 sn-p 可能是解决方案,但 including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
      • 有很多答案,比如“使用@PrimaryKey(autoGenerate = true)”——你的答案是否为这个线程添加了任何新内容?
      • 是的,它添加了 - 它展示了 null 如何覆盖自动生成的字段
      【解决方案8】:

      您可以像这样添加@PrimaryKey(autoGenerate = true)

      @Entity
      data class Food(
              var foodName: String, 
              var foodDesc: String, 
              var protein: Double, 
              var carbs: Double, 
              var fat: Double
      ){
          @PrimaryKey(autoGenerate = true)
          var foodId: Int = 0 // or foodId: Int? = null
          var calories: Double = 0.toDouble()
      }
      

      【讨论】:

      • foodId 不需要为空(但可以)。也可以使用默认值,例如。 var foodId: Int = 0 并且自动生成将正常工作。
      • @MichałBaran,来自 java doc,当类型是原始 java intlong,0 被视为可空,当类型为 Integer 或 Long 时,null 是可以为空。由于 Kotlin Int 当不可为空在 JVM 中作为原始 int 工作时,那么你是对的,var foodId: Int = 0 可以工作,但 var foodId: Int? = 0 将不能工作,因为 Int?在 JVM 中转换为整数。 @JMK,如果您将其设为 0,则出于上述原因,您必须创建一个不可为空的 int
      • 你可以不用其他方式写:val jack = User(name = "Jack", phone= 1) 在这种情况下你可以从构造函数中删除 0
      • 我看到这种方法的问题在于它是一个数据类。当 Food 是一个数据类时(如在 sn-p 中),food 用于 equals() 比较,因此可以认为具有不同 foodId 的两种食物是相等的。使用带有默认值的命名参数将解决这个问题。
      • @neer17 因为 foodId 将在插入时由 Room 自动生成,所以在构造函数中使用它更可能没有用。
      猜你喜欢
      • 1970-01-01
      • 2018-05-10
      • 1970-01-01
      • 2020-11-03
      • 1970-01-01
      • 2018-03-29
      • 2018-05-27
      • 2018-01-22
      • 1970-01-01
      相关资源
      最近更新 更多