如何使主键作为房间持久性库的自动增量

Posted

技术标签:

【中文标题】如何使主键作为房间持久性库的自动增量【英文标题】: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。 【参考方案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 自动生成,所以在构造函数中使用它更可能没有用。

以上是关于如何使主键作为房间持久性库的自动增量的主要内容,如果未能解决你的问题,请参考以下文章

如何返回自动增量ID,REST服务

如何使主键以特定字母开头?

插入房间后的行

房间持久性库。删除所有

如何将房间自动生成的主键作为外键添加到另一个实体

如何在房间持久性库中使用外键